<?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
解决问题 - 帮助赞赏!
答案 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
去图;)
根据您的情况,您可以使用圆形。但典型的解决方案是使用所谓的machine epsilon。你的情况就是
define ('EPS', 1e-15);
if (abs($foo - 0.8) < EPS) {
// ...
您的EPS的值显然取决于您的平台,但条件中使用的值还取决于您对该数字执行的算术运算的数量,因为每个操作都会导致更多的舍入错误。有关更多信息,请阅读维基文章。