function dec2sat( $decimal )
{
return $decimal * (10**8);
}
echo dec2sat(0.06999206); // result: 6999206 (float type)
var_dump(dec2sat(0.06999206) >= 6999206); // result: FALSE
每个人都可以向我解释为什么var_dump(dec2sat(0.06999206) >= 6999206);
返回FALSE吗?
经过测试:PHP 7.2.12,PHP 7.1.22,PHP 5.6.38
答案 0 :(得分:2)
您正在尝试比较float与integer。在那种情况下,PHP需要将float显式转换为整数。当您在下面运行代码时:
var_dump((int)dec2sat(0.06999206)); // 6999205
您将获得号码6999205,该号码显然少于6999206。
同一件事是当您尝试比较字符串与整数时。这将输出true:
var_dump('string' == 0); // true
这是您始终需要比较类型和值以避免这种行为的方式。下面的代码将输出true,这不是一个漂亮的解决方案,但是可以工作。还要尝试其他情况。
var_dump(round(dec2sat(0.06999206), 0) >= 6999206); // true
为什么会这样:
浮点数的精度有限。尽管它取决于系统,但PHP通常使用IEEE 754双精度格式,由于舍入为1.11e-16的顺序,它将提供最大的相对误差。非基本算术运算可能会产生较大的错误,并且,当然,在合并多个运算时必须考虑错误传播。
此外,在底数10中可精确表示为浮点数的有理数(如0.1或0.7)在底数2中不具有作为浮点数的精确表示,内部使用,无论尾数的大小如何。因此,如果不损失一点点精度,就不能将它们转换为内部二进制副本。这可能导致混乱的结果:例如,floor((0.1 + 0.7)* 10)通常将返回7而不是预期的8,因为内部表示形式将类似于7.9999999999999991118 ....
在我们的示例中,当您将所有隐藏的数字都删除到小数点后时,您将获得下一个结果:
var_dump(number_format(dec2sat(0.06999206), 30, '.', '')); // 6999205.999999999068677425384521484375
var_dump(number_format(dec2sat(0.06999206), 9, '.', '')); // 6999205.999999999
var_dump(number_format(dec2sat(0.06999206), 8, '.', '')); // 6999206.00000000
结论:
从不信任浮点数到最后一位,并且不直接比较浮点数是否相等。如果需要更高的精度,则可以使用任意精度的数学函数和gmp函数。
将您返回的值转换为整数,或者将其舍入到小数点后8位。
答案 1 :(得分:0)
function dec2sat($decimal)
{
return $decimal * (10 ** 8) . '';
}
答案 2 :(得分:0)
我要说的第一件事是:非常感谢您花费时间为我的问题找到解决方案。我的问题的主要目标不是找出解决方案,我需要知道导致上述意外结果的原因,因为它有助于避免以后重复。
在查看了AleksandarRakić的答案之后,我对PHP中的float类型进行了一些搜索,现在,我想我已经找到了导致var_dump(dec2sat(0.06999206) >= 6999206);
返回FALSE
的原因。您可以在这里阅读:Warning: Floating point precision
我认为数字0.06999206
并不是真的0.06999206
,在内部存储时可能是0.069992059999...
,而函数dec2sat(0.06999206)
的结果是6999205.999...
,这就是为什么AleksandarRakić的解决方案返回预期结果。
这是经过编辑的dec2sat()
function dec2sat( $decimal )
{
return intval(round( $decimal * (10**8) )); // $decimal always has decimal value <= 8 digits
}
函数dec2sat()
的主要目标是将floating point number
转换为int
以避免直接在我的应用程序中处理floating point number
。