为什么PHP对这种情况的评估不正确?

为什么PHP对这种情况的评估不正确?,php,floating-point,comparison,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

我在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
有什么想法吗?

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

以下几页讨论了为什么浮动作为货币是一个糟糕的想法:

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

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

以下几页讨论了为什么浮动作为货币是一个糟糕的想法:


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

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

原因是许多小数只能用浮点或双精度来近似。它们基于二进制分数,而不是十进制分数。一般来说,有理数a/b在a和b中没有公因子,当且仅当b的所有素数因子也是b的素数因子时,才可以用基数r表示法精确表示。例如,在十进制中,1/5是0.2,但1/3是0.333。。。在二进制中,1/5与十进制中的1/3产生相同的问题

在您的代码中,我建议在执行100的乘法后将小数点舍入到零位。整数向零舍入,这不是您所需要的。如果输入甚至略小于正整数n,则强制转换的结果为n-1。四舍五入的结果是n

无法精确表示的十进制分数的浮点表示可能比原始十进制分数稍低或稍高。如果从例如0.29开始,将其转换为最接近的IEEE 754 64位浮点,然后乘以100,实际上将得到相当于28.999999999964447286321199499070644378662109375的浮点值


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

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

原因是许多小数只能用浮点或双精度来近似。它们基于二进制分数,而不是十进制分数。一般来说,有理数a/b在a和b中没有公因子,当且仅当b的所有素数因子也是b的素数因子时,才可以用基数r表示法精确表示。例如,在十进制中,1/5是0.2,但1/3是0.333。。。在二进制中,1/5与十进制中的1/3产生相同的问题

在您的代码中,我建议在执行100的乘法后将小数点舍入到零位。整数向零舍入,这不是您所需要的。如果输入甚至略小于正整数n,则强制转换的结果为n-1。四舍五入的结果是n

无法精确表示的十进制分数的浮点表示可能比原始十进制分数稍低或稍高。如果从例如0.29开始,将其转换为最接近的IEEE 754 64位浮点,然后乘以100,实际上将得到相当于28.999999999964447286321199499070644378662109375的浮点值


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

看起来它只是将第一个变量转换为整数,但我可能错了。试着用括号括住马拉松,然后施放它。也许试着在if条件下施放,比如if int$eq_left!==int$eq_对吗?是否使用函数检查每个变量的类型?此外,第一个类型转换只转换第一个括号中的组。您可能希望将整个表达式类型转换为int$eq_bal_CurrentAssets*100+$eq_bal_NonCurrentAssets*100 Just use!=php不会检查相同的类型看起来它只是将第一个变量转换为int,但我可能错了。试着用括号括住马拉松,然后施放它。也许试着在if条件下施放

打开,就像int$eq_离开一样!==int$eq_对吗?是否使用函数检查每个变量的类型?此外,第一个类型转换只转换第一个括号中的组。您可能希望将整个表达式类型转换为int$eq_bal_CurrentAssets*100+$eq_bal_NonCurrentAssets*100 Just use!=php不会检查同一类型,One也可能会认为使用浮点数表示十进制时间是一个非常糟糕的主意。我曾经不得不使用一个时间记录系统,它遇到了这个问题。聚合时间与单个部分不对应。简直糟透了。这不适用于我的示例,因为我将值乘以100将它们转换为整数,所以不涉及浮点数。@PeterSnow:不,您没有。乘以100并不能把它们变成整数。你还有彩车。请参阅下面帕特里夏·沙纳汉的解释。@AndyLester感谢安迪告诉我这一点。不幸的是,我仍然无法理解为什么十进制乘以100不是整数,或者为什么当29.00乘以100后已经是“2900”时它仍然需要“舍入”,我认为这使它成为了整数!至少现在我知道我需要这方面的研究,我打算现在就做。感谢所有人:我在上面的回答中提供了三个链接。它们应该能帮助你理解。你也可以说用浮点数来表示十进制时间是一个非常糟糕的主意。我曾经不得不使用一个时间记录系统,它遇到了这个问题。聚合时间与单个部分不对应。简直糟透了。这不适用于我的示例,因为我将值乘以100将它们转换为整数,所以不涉及浮点数。@PeterSnow:不,您没有。乘以100并不能把它们变成整数。你还有彩车。请参阅下面帕特里夏·沙纳汉的解释。@AndyLester感谢安迪告诉我这一点。不幸的是,我仍然无法理解为什么十进制乘以100不是整数,或者为什么当29.00乘以100后已经是“2900”时它仍然需要“舍入”,我认为这使它成为了整数!至少现在我知道我需要这方面的研究,我打算现在就做。感谢所有人:我在上面的回答中提供了三个链接。他们应该可以帮助您理解。我无法通过在线解决方案找到问题的正确端到端解释,所以有人能告诉我这是否是货币的完整解决方案:当接收用户输入的数据时,乘以100,然后转换为INT。然后执行任何进一步的计算或比较,存储在数据库中,从数据库中检索,显示前除以100。这样行吗?我遗漏了什么吗?没有,如果你这样做,你必须在乘以100和转换为int之间舍入到零位小数。我在上面扩展了我的解释。因此,当我收到用户提供的输入时,我会做以下操作:舍入$v*100,0;,然后,当我需要再次显示它时,我将使用数字_格式$v/100,2',',',';。对吗?谢谢Patricia。我在网上找不到解决方案问题的正确端到端解释,所以有人能告诉我这是否是货币的完整解决方案吗:当收到用户输入的数据时,乘以100,然后转换为INT。然后执行任何进一步的计算或比较,存储在数据库中,从数据库中检索,显示前除以100。这样行吗?我遗漏了什么吗?没有,如果你这样做,你必须在乘以100和转换为int之间舍入到零位小数。我在上面扩展了我的解释。因此,当我收到用户提供的输入时,我会做以下操作:舍入$v*100,0;,然后,当我需要再次显示它时,我将使用数字_格式$v/100,2',',',';。对吗?谢谢帕特里夏。