为什么打印最后一个数字(1)?

代码:

<?php $start = 0; $stop = 1; $step = ($stop - $start)/10; $i = $start + $step; while ($i < $stop) { echo($i . "<br/>"); $i += $step; } ?> 

输出:

 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 <-- notice the 1 printed when it shouldn't 

创build了一个小提琴

另外:如果你设置$start = 1$stop = 2它工作正常。

使用: php 5.3.27

为什么打印1

因为不仅浮法math有缺陷,有时它的表示也是有缺陷的 – 在这里就是这种情况。

你实际上不会得到0.1,0.2,… – 这很容易检查:

 $start = 0; $stop = 1; $step = ($stop - $start)/10; $i = $start + $step; while ($i < $stop) { print(number_format($i, 32) . "<br />"); $i += $step; } 

这里唯一的区别就在于,这个echonumber_format调用取代。 但结果却截然不同:

 0.10000000000000000555111512312578 0.20000000000000001110223024625157 0.30000000000000004440892098500626 0.40000000000000002220446049250313 0.50000000000000000000000000000000 0.59999999999999997779553950749687 0.69999999999999995559107901499374 0.79999999999999993338661852249061 0.89999999999999991118215802998748 0.99999999999999988897769753748435 

看到? 实际上只有一次是0.5 ,因为这个数字可以存储在浮动容器中。 所有其他人只是近似。

如何解决这个问题? 那么,一个激进的方法是使用不漂浮,但在整体类似的情况。 很容易注意到,你是这样做的…

 $start = 0; $stop = 10; $step = (int)(($stop - $start) / 10); $i = $start + $step; while ($i < $stop) { print(number_format($i, 32) . "<br />"); $i += $step; } 

…它会工作正常:

或者,您可以使用number_format将float转换为某个string,然后将此string与预格式化的float进行比较。 喜欢这个:

 $start = 0; $stop = 1; $step = ($stop - $start) / 10; $i = $start + $step; while (number_format($i, 1) !== number_format($stop, 1)) { print(number_format($i, 32) . "\n"); $i += $step; } 

问题是variables$ i中的数字不是1(打印时)。 因此,在testing中($ i <$ stop)是真的,数字被转换成十进制(导致舍入为1),并显示出来。

现在为什么我不是1? 这是因为你通过说10 * 0.1来到那里,0.1不能用二进制完美表示。 只有可以表示为有限数目2的幂的和的数字才能被完美地表示。

为什么那么$是完全停止1? 因为它不是浮点格式。 换句话说,它从一开始就是确切的 – 它不会在系统内使用浮点数10 * 0.1来计算。

在math上,我们可以这样写: 在这里输入图像说明

一个64位的二进制浮点只能容纳总和近似0.1的前27个非零项。 有效数的其余26位保持为零以指示零项。 0.1的原因在物理上不能代表的是,所需的术语序列是无限的。 另一方面,像1这样的数字只需要有限数量的术语并且是可表示的。 我们希望这是所有数字的情况。 这就是为什么十进制浮点是如此重要的创新(尚未广泛使用)。 它可以代表我们可以写下的任何数字,并且完美地完成。 当然,可用数字的数量仍然是有限的。

回到给定的问题,因为0.1是循环variables的增量,并且实际上不是可表示的,所以在循环中从未精确地达到值1.0(尽pipe可表示)。

如果你的步骤总是10的因素,你可以用下面的方法快速完成:

 <?php $start = 0; $stop = 1; $step = ($stop - $start)/10; $i = $start + $step; while (round($i, 1) < $stop) { //Added round() to the while statement echo($i . "<br/>"); $i += $step; } ?>