为什么PHP对这个条件的计算不正确?


floating point - Why does PHP appear to evaluate this condition incorrectly?

我在PHP中有以下代码,我试图通过将变量类型强制转换为整数来克服上述问题,并通过在比较之前将所有值乘以100以消除2位小数点来避免浮点错误。

然而,下面的代码仍然计算表达式为true,并将文本显示为红色而不是绿色,但是当我回显$eq_left和$eq_right的两个值时,它们是相同的,没有小数点。

代码如下:

$eq_left    = (int) ($eq_bal_CurrentAssets*100) + ($eq_bal_NonCurrentAssets*100) ;
$eq_right   = (int) ($eq_bal_Liabilities*100) + ($eq_bal_Taxation*100) + ($eq_bal_Equity*100) ;
if ($eq_left !== $eq_right) {
    $color = 'red';
    $diff   = abs($eq_left - $eq_right);
} else {
    $color = 'green';
}
echo "<div style='"color: $color; font-weight:bold;'">'n";
echo "  " . number_format(($eq_left/100),2,".",",") . " = " . number_format(($eq_right/100),2,".",",") . "<br />'n";
if ($diff) {
    echo "      Difference = " . number_format(($diff/100),2,".",",") . "'n";
}
echo "</div>'n";
echo $eq_left . " | " . $eq_right

任何想法?

如果您想要精确的小数表示,我同意不要使用浮点数的建议。

原因是许多小数只能用浮点数或双精度来近似。它们是基于二进制分数,而不是十进制分数。一般来说,一个有理数a/b,在a和b没有公因数的情况下,当且仅当b的所有质因数都是b的质因数时,可以精确地用基数r表示。例如,在十进制中,1/5等于0.2,而1/3等于0.333333333…在二进制系统中,1/5和十进制系统中的1/3会产生同样的问题。

在您的代码中,我建议在乘以100后将小数点四舍五入到零。(int)强制转换向零舍入,这不是您需要的。如果输入比正整数n小一点点,则强制转换的结果是n-1。round的结果为n。

不能精确表示的小数的浮点表示形式可能比原始小数略低或略高。如果您从0.29开始,将其转换为最接近的IEEE 754 64位浮点数,并乘以100,您将实际得到28.99999999999999996447286321199499070644378662109375的浮点等效物

将其转换为整数并向零四舍五入得到28,而不是29。四舍五入到最接近的整数将得到29。

永远不要用浮点数表示货币。总是将货币值存储为整数分。将5.40美元存储为540,并在需要显示时除以100。浮点数不能准确地表示您所认为的小数。

这里有一些页面讨论为什么浮动作为货币是一个糟糕的想法:

  • 为什么不使用Double或Float来表示货币?
  • 在mysql中存储钱款
  • 如果在float中处理金钱是不好的,那么为什么money_format()这样做?

您遇到的问题是小数的浮点表示所固有的。唯一可靠地绕过它们的方法是使用整数。