如果仍然有人在访问此页面时遇到类似的问题,其中浮点数减法会导致错误或奇怪的值。下面我将更详细地解释这个问题。
它与 PHP 没有直接关系,也不是错误。但是,每个程序员都应该意识到这个问题。
二十年前,这个问题甚至夺走了许多人的生命。
1991 年 2 月 25 日,MIM-104 爱国者导弹连中的一个不正确的浮点运算(称为舍入误差)阻止了它在沙特阿拉伯达兰拦截一枚飞毛腿导弹,造成 28 名士兵死亡,近 100 名美军第 14 师的士兵受伤。军需支队。
但为什么会发生呢?
原因是浮点值表示有限的精度。因此,在任何处理(截断)之后,值可能不会具有相同的字符串表示形式。它还包括在脚本中编写一个浮点值并直接打印它而无需任何数学运算。
只是一个简单的例子:
$a = '36';
$b = '-35.99';
echo ($a + $b);
你会期望它打印0.01
,对吧?但它会打印一个非常奇怪的答案,比如0.009999999999998
与其他数字一样,浮点数 double 或 float 以 0 和 1 的字符串形式存储在内存中。浮点数与整数的不同之处在于我们在查看 0 和 1 时如何解释它们。它们的存储方式有很多标准。
浮点数通常作为符号位、指数字段和有效数或尾数从左到右打包到计算机数据中......
由于缺少足够的空间,十进制数不能很好地用二进制表示。所以,你不能1/3
完全按原样表达0.3333333...
,对吧?为什么我们不能表示0.01
为二进制浮点数是出于同样的原因。1/100
是0.00000010100011110101110000.....
带重复的10100011110101110000
。
如果以二进制0.01
的简化和系统截断形式保存01000111101011100001010
,当它被转换回十进制时,它的读取方式将0.0099999....
取决于系统(64 位计算机将提供比 32 位更好的精度)。在这种情况下,操作系统决定是否按照它看到的方式打印它,或者如何以更易于阅读的方式进行打印。因此,他们想要如何表示它取决于机器。但是可以用不同的方法在语言级别上进行保护。
如果您使用格式化结果
echo number_format(0.009999999999998, 2);
它会打印0.01
。
这是因为在这种情况下,您指示应该如何阅读它以及您需要多高的精度。
注意 number_format() 不是唯一的函数,还有一些其他函数和方法可以用来告诉编程语言关于精度期望的信息。
参考文献:
https ://sdqweb.ipd.kit.edu/publications/pdfs/saglam2016a.pdf
https://en.wikipedia.org/wiki/Round-off_error