为何选择FLOAT!= FLOAT

时间:2012-09-28 07:17:35

标签: php floating-point

$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)

对此有何解释?

3 个答案:

答案 0 :(得分:5)

100/3会产生33.3-repeating

没有小数点值可以显示它。在数学中,这样的数字通常在重复值上用小点表示。 (虽然我不知道如何在这个代码框中显示它。)

请参阅此wiki article,了解它们在不同地方的表现方式,以及我在此提供的更为详细的解释。

但是,从这篇文章中可以看到摘要的片段:

  

在算术中,重复十进制是表示有理数的一种方式。因此,数字的十进制表示称为重复十进制(或重复十进制),如果在某些时刻它变为周期性的,即,如果有一些有限的数字序列无限重复。例如,十进制表示1/3 = 0.3333333 ...或0.3(表示为“0.3重复”或“0.3重复”)在小数点之后变为周期性,无限地重复单个数字序列“3”。一个稍微复杂的例子是3227/555 = 5.8144144144 ...,其中十进制表示在小数点后的第二个数字处成为周期性的,无限期地重复数字“144”的序列。

现在,这是你的问题的关键所在,但也要记住(正如其他两个答案所指出的那样)浮动在计算和比较方面令人惊讶地 innacurate 。快速搜索这个网站将揭示一小群人在浮标的内部表示方面存在问题 - 主要是在进行比较时导致意外行为。

float data type上仔细阅读PHP警告 - 我再次复制了重要的一点:

  

此外,基本10中的浮点数精确表示的有理数,如0.1或0.7,没有精确表示为基数2中的浮点数,无论尾数的大小如何,它都在内部使用。因此,它们不能在没有很小精度损失的情况下转换为它们的内部二进制对应物。这可能会导致令人困惑的结果:例如,floor((0.1 + 0.7)* 10)通常会返回7而不是预期的8,因为内部表示将类似于7.9999999999999991118 ....

答案 1 :(得分:1)

并非所有float都可以由处理器完全表示。 $a/$b就是其中之一。

所以,$test1 != $test2是真的。

答案 2 :(得分:1)

来自 PHP

的信息
  

警告

     

浮点精度

     

浮点数的精度有限。虽然这取决于   在系统中,PHP通常使用IEEE 754双精度格式,   由于订单的舍入,这将产生最大的相对误差   1.11e-16。非基本算术运算可能会更大   错误,当然,必须考虑错误传播   几个操作复杂化。

     

此外,有理数的数字可以完全表示为   基数10中的浮点数,如0.1或0.7,没有   精确表示为基数2中的浮点数,即   内部使用,无论尾数的大小。因此,他们   没有a就无法转换成它们的内部二进制对应物   精度损失小。这可能导致令人困惑的结果:for   例如,floor((0.1 + 0.7)* 10)通常会返回7而不是   预期8,因为内部表示将是类似的   7.9999999999999991118 ....

     

所以永远不要将浮动数字结果信任到最后一位数,而不是   直接比较浮点数是否相等。如果更高   精度是必要的,任意精度数学函数和gmp   功能可用。

如上面的警告中所述,测试浮点值的相等性是有问题的,因为它们在内部表示的方式。但是,有一些方法可以比较浮点值,这些值可以解决这些限制。

要测试浮点值是否相等,使用由于舍入引起的相对误差的上限。此值称为machine epsilon或单位舍入,是计算中可接受的最小差异。

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