php 为什么要浮动!=浮动[重复]

iszxjhcz  于 2023-03-11  发布在  PHP
关注(0)|答案(3)|浏览(132)

此问题在此处已有答案

(17个答案)
Comparing floats - same number, but does not equal? [duplicate](3个答案)
(31个答案)
昨天关闭。

$a     = 100;
$b     = 3;
$test1 = $a/ $b;
$test2 = 33.333333333333;  // $test2 == $test1

var_dump(($test1 * $b));   // float(100)
var_dump(($test2 * $b));   // float(99.999999999999)

对此有何解释?

c7rzv4ha

c7rzv4ha1#

100/3的结果是33.3-repeating
没有小数点值会显示它。在数学中,这样的数字通常用重复值上的一个小点来表示。(尽管我不知道如何在这个代码框中显示)。
请参考这个wiki article,了解它们在不同地方的表示方式,以及我在这里给出的更详细的解释。
然而,从文章这里是一个摘要的片段:
在算术中,循环小数是表示有理数的一种方法。因此,用小数表示一个数被称为循环小数(或循环小数),如果在某个点它变成周期性的,也就是说,如果有一些有限的数字序列无限重复。例如,1/3的十进制表示法= 0.3333333...或0.3(被称为“0.3重复”或“0.3循环”)在小数点之后变成周期性的,无限地重复一位数序列“3”。一个稍微复杂的例子是3227/555 = 5.8144144144...,其中十进制表示在小数点后的第二位数处变成周期性的,无限地重复数字序列“144”。
现在,这就是问题的关键所在,但也要记住(正如其他两个答案所指出的),浮点数在计算和比较方面是惊人的“固有”。快速搜索这个网站就会发现,有一小群人在浮点数的内部表示方面遇到了问题--主要是在进行比较时导致了意外的行为。
仔细阅读float data type上的PHP警告-我在这里再次复制了重要的部分:
此外,有理数可以精确地表示为以10为底的浮点数,如0.1或0.7,而不具有以2为底的浮点数的精确表示,后者是内部使用的,无论尾数的大小如何。因此,它们无法在不损失少量精度的情况下转换为它们的内部二进制对应物。这可能会导致混乱的结果:例如,floor((0.1+0.7)*10)通常会返回7而不是预期的8,因为内部表示形式类似于7.9999999999999999991118...。

zy1mlcev

zy1mlcev2#

并不是所有的float都能用处理器精确地表示,$a/$b就是其中之一。
所以$test1 != $test2是真的。

oknwwptz

oknwwptz3#

来自**PHP**的信息

警告
浮点精度

浮点数的精度是有限的。虽然它取决于系统,PHP通常使用IEEE 754双精度格式,这将给予一个最大的相对误差,因为舍入的顺序为1.11e-16。非初等算术运算可能会给出更大的误差,当然,当几个运算复合时,必须考虑误差传播。
此外,有理数可以精确地表示为以10为底的浮点数,如0.1或0.7,而不具有以2为底的浮点数的精确表示,后者是内部使用的,无论尾数的大小如何。因此,它们无法在不损失少量精度的情况下转换为它们的内部二进制对应物。这可能会导致混乱的结果:例如,floor((0.1+0.7)*10)通常会返回7而不是预期的8,因为内部表示形式类似于7.9999999999999999991118...。
所以永远不要相信浮点数的最后一位,也不要直接比较浮点数是否相等,如果需要更高的精度,可以使用任意精度的数学函数和gmp函数。
正如上面的警告所指出的,由于浮点值的内部表示方式,测试浮点值是否相等是有问题的。但是,有一些方法可以绕过这些限制来比较浮点值。
要测试浮点值是否相等,请使用舍入引起的相对误差的上限。此值称为machine epsilon或单位舍入,是计算中可接受的最小差值。

非常感谢所有花时间回答我问题的人

相关问题