2

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

有任何想法吗?

4

2 回答 2

3

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

原因是许多小数只能用浮点数或双精度数来近似。它们基于二进制而不是十进制分数。一般而言,当且仅当 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。

于 2012-12-22T07:28:16.153 回答
1

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

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

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

于 2012-12-22T05:06:17.407 回答