PHP异常/奇怪的行为

时间:2012-11-07 23:15:08

标签: php floating-point

当我跑步时:

for($o=1;$o<=655;$o++){ $r = $r+0.01; echo $r." ";}

在某些时候我得到了:

...4.29 4.3 4.31 4.32 4.33 4.34 4.35 4.36 4.37 4.38 4.39 4.4
4.41 4.42 4.4299999999999 4.4399999999999 4.4499999999999
4.4599999999999 4.4699999999999 ...

但是当我跑步时:

for($o=1;$o<=5;$o+=0.01){ echo $o." "; }

异常开始于:

4.34 4.35 4.36 4.37 4.38 4.3899999999999 4.3999999999999

为什么添加是for循环的一部分,或者在for循环中有什么区别?

4 个答案:

答案 0 :(得分:5)

欢迎来到舍入错误的奇迹。

0.01并不能完全表达为有限二进制分数,因此如果将其重复添加到另一个浮点数,最终会得到舍入误差。

您看到舍入误差的具体点取决于所涉及数字的二进制展开如何产生舍入误差。

答案 1 :(得分:1)

浮点数学不能准确表示值。请参阅here

答案 2 :(得分:0)

您可以使用Round()函数。这是一个链接: http://php.net/manual/en/function.round.php

答案 3 :(得分:0)

当数字“.01”转换为64位IEEE 754二进制浮点时,结果为0.010000000000000000208166817117216851329430937767028809。当$ r设置为0,并且此近似值.01被添加100次时,结果为1.0000000000000006661338147750939242541790008544921875,原因是添加期间出现了额外的舍入误差。

现在考虑$ r从这个值稍微超过1进一步增加,而$ o从它的起始值正好增加1.首先,因为$ r和$ o以不同的值开始,它们通常会有不同的值后来。其次,因为它们是不同的,因为增量被添加到它们中的每一个,它们在添加中的四舍五入中遇到不同的错误。这种错误可能会强化或取消,导致$ r或$ o或多或少不同。

最后,PHP有一些判断是否打印带小数点后两位数的数字的标准。据推测,在某些时候,$ r或$ o的值与最接近的数字相距足够远,有两个小数点,PHP决定它应该打印更多的数字。如上所述,这发生在$ r和$ o的不同时间。