为什么PHP似乎错误地评估了这种情况?

时间:2012-12-22 04:39:58

标签: php floating-point comparison

我在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

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

如果您想要精确的小数部分表示,我同意针对浮点的建议。

原因是许多小数部分只能以float或double近似。它们基于二进制,而不是十进制,分数。一般而言,如果且仅当b的所有素因子也是b的素因子时,a和b中没有共同因子的有理数a / b可以精确地表示在基数r表示中。例如,十进制1/5为0.2,但1/3为0.333333333 ...在二进制系统中,1/5导致与十进制的1/3相同的问题。

在你的代码中,我建议在乘以100后舍入到零小数位。(int)强制转向零,这不是你需要的。如果输入甚至略小于正整数n,则转换的结果为n-1。回合的结果是n。

无法精确表示的小数部分的浮点表示可能略低于或略高于原始小数部分。如果你从例如开始0.29,将其转换为最接近的IEEE 754 64位浮点数,乘以100,实际上得到的浮点数相当于28.999999999999996447286321199499070644378662109375

将其转换为int,舍入为零,得到28,而不是29.将它舍入到最接近的int将得到29。

答案 1 :(得分:1)

永远不要使用浮点数来赚钱。始终将货币值存储为整数美分。当你想要显示时,你将$ 5.40存储为540并除以100。浮点数不能准确表示您认为的小数。

这里有一些页面讨论为什么花钱作为一个可怕的想法:

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