PHP舍入错误

Les*_*czu 10 php rounding-error rounding

我在我的linux服务器上使用PHP 5.2.13.在舍入数字时,我遇到了奇怪的错误.这是我的测试用例:

<?php
echo "        " . round(1.505, 2) . "\n";
echo "       " . round(11.505, 2) . "\n";
echo "      " . round(111.505, 2) . "\n";
echo "     " . round(1111.505, 2) . "\n";
echo "    " . round(11111.505, 2) . "\n";
echo "   " . round(111111.505, 2) . "\n";
echo "  " . round(1111111.505, 2) . "\n";
echo " " . round(11111111.505, 2) . "\n";
echo "" . round(111111111.505, 2) . "\n";
Run Code Online (Sandbox Code Playgroud)

这是结果:

        1.51
       11.51
      111.51
     1111.51
    11111.51
   111111.51
  1111111.5
 11111111.51
111111111.51
Run Code Online (Sandbox Code Playgroud)

谁知道是什么原因造成的?我无法更新PHP,因为它是共享服务器.

Kib*_*bee 11

这是因为数字1111111.505无法用浮点表示法精确表示.它最接近的是1111111.5049999999.所以最终发生的是它将代码中的数字转换为1111111.50499999999,然后进行舍入.其中结果为1111111.5.浮点数有问题,因为它们不能完全准确地表示很多看似简单的十进制数.例如.使用二进制浮点数无法准确表示数字0.1.使用Python,如果输入0.1,则返回0.10000000000001.加或减几个零.这就是某些语言(如.Net)提供"十进制"数据类型的原因,该数据类型能够表示特定范围内的所有十进制值和小数位数.十进制数据类型的缺点是速度较慢,每个数字需要更多空间来存储.


Sel*_*lay 6

如果仍然有人到达此页面时遇到类似的问题,其中浮数减法会导致错误或奇怪的值。我想用更多细节来解释这个问题。罪魁祸首是浮点数。为了说明这个问题,我将用一个简单的例子来说明为什么,然后您可以从中假设它为什么影响舍入等。

它与PHP没有直接关系,也不是bug。但是,每个程序员都应注意此问题。

这个问题甚至在二十年前夺走了许多生命。

1991年2月25日,MIM-104爱国者导弹电池中的浮点计算问题阻止了它在沙特阿拉伯的达兰拦截到来的飞毛腿导弹的拦截,导致美军第14军需长联队的28名士兵死亡。

但是为什么会这样呢?

原因是浮点值表示有限的精度。因此,在进行任何处理后,值可能不会具有相同的字符串表示形式。它还包括在脚本中编写浮点值并直接打印而无需任何数学运算。

只是一个简单的例子:

$a = '36';
$b = '-35.99';
echo ($a + $b);
Run Code Online (Sandbox Code Playgroud)

您希望它可以打印0.01,对吗?但是它会打印出一个非常奇怪的答案,如0.009999999999998

与其他数字一样,双精度浮点数或双精度浮点数以0和1的字符串形式存储在内存中。浮点与整数的不同之处在于当我们要查看它们时如何解释0和1。有许多标准存储它们。

浮点数通常作为符号位,指数字段以及有效位数或尾数从左到右打包到计算机数据中。

由于缺少足够的空间,因此十进制数不能很好地用二进制表示。所以,您不能完全按照1/3的0.3333333来表达1/3,对吧?出于同样的原因,为什么不能将0.01表示为二进制浮点数。1/100是0.00000010100011110101110000 .....,重复10100011110101110000。

如果以二进制形式将01000111101011100001010的简化形式和系统截断形式的0.01保留为二进制,则将其转换回十进制时,其读数将像0.0099999....。具体取决于系统(64位计算机的精度要比32位更好) )。在这种情况下,操作系统将决定是否按其外观进行打印或如何以更易于理解的方式进行打印。因此,它们如何表示它取决于机器。但是可以使用不同的方法在语言级别进行保护。

如果格式化结果,则回显number_format(0.009999999999998,2); 它将打印0.01。

这是因为在这种情况下,您需要指导如何阅读和要求精度。参考文献:1,2,3,4,5

  • 更深入地了解内部时钟是如何工作的。该示例是在大学中教授的,并以其原始源代码进行说明。“由于爱国者计算机执行计算的方式以及其寄存器只有 24 位长,时间从整数到实数的转换不可能比 24 位更精确”。https://www.cs.drexel.edu/~introcs/Fa10/notes/07.1_FloatingPoint/Patriot.html?CurrentSlide=10 (2认同)