了解php中的浮点数

时间:2012-06-12 06:48:41

标签: php floating-point floating-accuracy

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

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

例如......

$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/这样的页面似乎有简单的问题而且我没有得到它。

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

6 个答案:

答案 0 :(得分: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)。

答案 1 :(得分:2)

这是一个明显的例子:

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

您会希望打印1,但实际输出为0.99999999999808

(结果在x86_64架构上)

答案 2 :(得分:1)

浮点数越大(或越小),它就越不精确。确切地说,精确度将根据处理器架构而有所不同。

尝试在1E30或1E-30 ...

进行所有测试

答案 3 :(得分:1)

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

我不打算触及第三个,因为它应该是显而易见的原因。

对于第四个,使用的值具有明确定义的,完全准确的位模式。尝试使用更多的数字。

答案 4 :(得分:0)

你可以尝试

 $a = '12.30';

作为字符串以获得完全匹配,否则floatbox默认删除结尾为'0'。

答案 5 :(得分:0)

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

在第一个示例中,将“27.64”分配给$ num1和$ num2。这里有一个操作:解析器必须解释字符串“27.64”并产生一个浮点结果。可能,解析器生成最接近27.64的浮点数。 (作为十六进制浮点数,该数字为0x1.ba3d70a3d70a4p + 4.“p”之前的部分是十六进制数字,带有小数部分。“p4”表示乘以2 4 。作为十进制数字,它是27.6400000000000005684341886080801486968994140625。)并且它在两种情况下产生相同的数字,因此$ 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),略低于.3。将“.1”转换为浮点会产生最接近的可表示值,即0x1.999999999999ap-4(0.1000000000000000055511151231257827021181583404541015625),略高于.1。将“.2”转换为浮点数会产生最接近的可表示值,即0x1.999999999999ap-3(0.200000000000000011102230246251565404236316680908203125),略高于.2。添加后两个值会产生最接近其总和的可表示值,即0x1.3333333333334p-2(0.3000000000000000444089209850062616169452667236328125)。如您所见,该总和与通过将“.3”转换为浮点所获得的值不同,因此比较它们表明它们是不相等的。