奇怪的PHP浮点行为

som*_*ame 1 php floating-point

有奇怪的问题:

$testTotal = 0;
foreach($completeBankArray as $bank){
   var_dump($testTotal);
   echo  " + ";
   var_dump(floatval($bank["amount"]));
   echo " = ".(floatval($testTotal) + floatval($bank["amount"]))."</br>";
   $testTotal = floatval(floatval($testTotal) + floatval($bank["amount"]));
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出:

------------------//--------------------
float(282486.09) + float(15) = 282501.09
float(282501.09) + float(3.49) = 282504.58
float(282504.58) + float(22.98) = 282527.55999999
float(282527.55999999) + float(5.2) = 282532.76
float(282532.76) + float(39.98) = 282572.73999999
float(282572.73999999) + float(2.6) = 282575.33999999
float(282575.33999999) + float(2.99) = 282578.32999999 
------------------//----------------------- 
Run Code Online (Sandbox Code Playgroud)

这怎么可能,我在做什么呢?

Flu*_*feh 7

你没有做错任何事.漂浮物众所周知是无用的.从文档(在巨大的红色警告框中):

浮点数的精度有限.虽然它取决于系统,但PHP通常使用IEEE 754双精度格式,由于舍入的顺序为1.11e-16,因此会产生最大的相对误差.非基本算术运算可能会产生更大的误差,当然,当复合多个运算时,必须考虑误差传播.

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

因此,永远不要将浮点数结果信任到最后一位,并且不要直接比较浮点数是否相等.如果需要更高的精度,可以使用任意精度数学函数gmp函数.