浮动的do-while指数说:0.8< 0.8

时间:2012-01-29 11:12:35

标签: php

  

可能重复:
  The accuracy of PHP float calculate

<?php
    $foo = 0;
    do {
        echo "\$foo = $foo".($foo >= 0.8 ? " >= 0.8<br>\n" : " < 0.8<br>\n");
        $foo = $foo + 0.1;
    } while($foo <= 1);
?>

导致以下输出:

$foo = 0 < 0.8
$foo = 0.1 < 0.8
$foo = 0.2 < 0.8
$foo = 0.3 < 0.8
$foo = 0.4 < 0.8
$foo = 0.5 < 0.8
$foo = 0.6 < 0.8
$foo = 0.7 < 0.8
$foo = 0.8 < 0.8
$foo = 0.9 >= 0.8
$foo = 1 >= 0.8

..甚至var_dump并没有告诉我更多它是0.8。吓人:

round($foo,1) >= 0.8

解决问题 - 帮助赞赏!

4 个答案:

答案 0 :(得分:3)

另一个floating point accuracy problem。您认为0.8对于计算机来说并不完全是0.8(尽管他甚至可能输出0.8)。

答案 1 :(得分:2)

只是标准的浮点舍入问题。

典型的float-to-string转换会丢弃最不重要的二进制数字,因此显示为0.8的两个数字不一定相同。由于0.8无法使用二进制浮点表示,因此它们都不是0.8

答案 2 :(得分:2)

问题是你不能在二进制浮点中精确表示0.8。你也不可能完全代表0.1。因此,使用0.1的不精确值来计算0.8将不太可能匹配0.8的不精确值。

答案 3 :(得分:2)

补充其他答案:

<?php
$foo = 0;

do {
    echo sprintf('%.16f %s 0.8', $foo, $foo >= 0.8 ? '>=' : '<') . PHP_EOL;
    $foo = $foo + 0.1;
} while($foo <= 1);

产生

0.0000000000000000 < 0.8
0.1000000000000000 < 0.8
0.2000000000000000 < 0.8
0.3000000000000000 < 0.8
0.4000000000000000 < 0.8
0.5000000000000000 < 0.8
0.6000000000000000 < 0.8
0.7000000000000000 < 0.8
0.7999999999999999 < 0.8
0.8999999999999999 >= 0.8
0.9999999999999999 >= 0.8

http://ideone.com/ggbMl

去图;)


根据您的情况,您可以使用圆形。但典型的解决方案是使用所谓的machine epsilon。你的情况就是

define ('EPS', 1e-15);
if (abs($foo - 0.8) < EPS) {
  // ...

您的EPS的值显然取决于您的平台,但条件中使用的值还取决于您对该数字执行的算术运算的数量,因为每个操作都会导致更多的舍入错误。有关更多信息,请阅读维基文章。