4

我知道这些问题可能会被问到很多,但是从我的阅读和测试来看,这让我有点困惑,而且我所做的很多阅读让我更加困惑,因为它非常复杂。

有些人似乎对简单的比较有问题,但我自己没有问题。

例如...

$num1 = 27.64;
$num2 = 27.64;

if ($num1 == $num2) {
    echo 'Good!';
} else {
    echo 'Bad!';
}

// Echo's "Good!"

...和

$num1 = 27.60;
$num2 = 27.6;

if ($num1 == $num2) {
    echo 'Good!';
} else {
    echo 'Bad!';
}

// Echo's Good

...和

$num1 = 27.60;
$num2 = 57.60;

if ($num1 <= $num2) {
    echo 'Good!';
} else {
    echo 'Bad!';
}

// Echo's Good

...和

$num1 = 25.00;
$num2 = 12.50 + 12.5;

if ($num1 == $num2) {
    echo 'Good!';
} else {
    echo 'Bad!';
}

// Echo's Good

然后我看到像http://patchlog.com/php/comparing-float-values-in-php/这样的页面似乎有简单的问题,我不明白。

我只是想了解他的简单代码是如何遇到问题的,但我不同意我的。

4

6 回答 6

3

示例 1

这些值将是相同的——您为每个变量分配相同的十进制文字。将其与此代码进行比较:

$num1 = 27.64;
$num2 = 10.0 + 2.88 + 2.88 + 2.88 + 9.0; //In decimal arithmetic adds to 27.64

if ($num1 == $num2) {
    echo 'Good!';
} else {
    echo 'Bad!';
}

// Echo's "Bad!"

$num2 看起来应该是 27.64,但它确实增加了 27.639999999999997015720509807579219341278076171875 (这就是我在我的机器上用 Visual C++ 进行计算时得到的结果)。$num1 = 27.6400000000000005684341886080801486968994140625(在我的机器上),所以它们不同。

示例 2

尾随的 0 没有区别。

示例 3

这些数字不在浮点“公差”范围内,因此当然会有所不同。

示例 4

12.5 完全可以用浮点表示,所以 12.5 + 12.5 也是(0.5 是 2^-1)。

于 2012-06-12T12:53:39.557 回答
2

这是一个明显的例子:

$a = 0;
for ($i = 0; $i < 100000; $i++) {
    $a += 0.00001;
}
print("$a\n");

你会期望你会被1打印出来,但实际上输出是0.99999999999808.

(结果是在 x86_64 架构上)

于 2012-06-12T06:53:50.660 回答
1

浮点数越大(或越小),精度就越低。确切的精确度会因处理器架构而异。

尝试在 1E30 或 1E-30 进行所有测试...

于 2012-06-12T06:51:28.320 回答
1

前两个具有编译器提供的值,它将两个数字解析为相同的位模式。

我不会触及第三个,因为它的工作原理应该很明显。

对于第四个,使用的值具有定义明确、完全准确的位模式。尝试在人迹罕至的地方使用更多的数字。

于 2012-06-12T06:52:54.843 回答
0

你可以试试

 $a = '12.30';

作为字符串以获得完全匹配,否则默认情况下浮动框删除结尾“0”。

于 2012-06-12T07:30:40.440 回答
0

浮点错误仅在存在数学结果不能以浮点精确表示的运算时发生。错误被精确定义;它们不是随机的或任意的,因此当执行相同的操作时会产生相同的结果。

在您的第一个示例中,您将“27.64”分配给 $num1 和 $num2。这里有一个操作:解析器必须解释字符串“27.64”并产生一个浮点结果。解析器很可能会生成最接近 27.64 的浮点数。(作为十六进制浮点数,该数字为 0x1.ba3d70a3d70a4p+4。“p”之前的部分是十六进制数字,带有小数部分。“p4”表示乘以 2 4。作为十进制数字,它是 27.64000000000000005684341886080801486968994140625。)它在两种情况下都产生相同的数字,因此 $num1 与 $num2 的比较表明它们彼此相等,尽管两者都不等于 27.64(因为 27.64 不能用浮点数精确表示)。

在您的第二个示例中,最接近数字“27.60”的值的浮点数与最接近数字“27.6”的值的浮点数相同,因为这两个数字代表相同的值。所以,再次,你会得到相同的结果。

在您的第三个示例中,两个数字的值相距甚远,因此您得到不同的浮点数,并且比较表明它们不相等。

在您的第四个示例中,所有值都可以用浮点数精确表示,因此没有错误。25、12.50 和 12.5 都是 2 的幂的小倍数(包括负指数的幂,例如 .5 = 2 -1,在浮点类型的范围内,因此它们是可表示的。此外, 12.50和12.5的和是完全可表示的,所以相加没有舍入误差,所以所有的结果都是准确的,比较是和等于25。

当人们期望从两个具有相同数学结果的不同计算中得到相同的结果时,就会出现问题。一个经典的例子是将“.3”与“.1+.2”进行比较。将数字“.3”转换为浮点会产生最接近的可表示值,即 0x1.3333333333333p-2 (0.299999999999999988897769753748434595763683319091796875),略低于 0.3。将“.1”转换为浮点会产生最接近的可表示值,即 0x1.999999999999ap-4 (0.1000000000000000055511151231257827021181583404541015625),略高于 0.1。将“.2”转换为浮点会产生最接近的可表示值,即 0x1.999999999999ap-3 (0.200000000000000011102230246251565404236316680908203125),略高于 0.2。将后两个值相加得到最接近它们总和的可表示值,即 0x1.3333333333334p-2 (0. 3000000000000000444089209850062616169452667236328125)。如您所见,该总和与将“.3”转换为浮点获得的值不同,因此比较它们表明它们不相等。

于 2012-06-12T15:00:59.727 回答