再次遇到另一个数学计算问题。
$a = 34.56
$b = 34.55
$a
做一些计算来得到这个数字
$b
正在进行最接近0.05的舍入以获得此数字
发生了什么
$c = $b - $a
据说我应该是-0.01,但我回应$c
显示-0.00988888888888
我尝试使用n umber_format($c, 2)
,但输出为0.00,
如何确保$a
和$b
正好是2位小数,后面没有隐藏号码。
在我的php知识中number_format只能格式化显示,但值实际上不是2位小数,
我希望我能从这里得到帮助。这让我非常沮丧。
答案 0 :(得分:41)
尝试sprintf
("%.2f", $c);
浮点数用IEEE表示法表示,基于2的幂,因此终止十进制数可能不是终止二进制数,这就是你获得尾随数字的原因。
正如可变长度编码器所建议的那样,如果你知道你想要的精度并且它没有改变(例如,当你处理钱时),最好只使用定点数,即将数字表示为分数而不是比美元
$a = 3456;
$b = 3455;
$c = $b - $a;
sprintf ("%.2f", $c/100.0);
这样,如果在打印前进行大量计算,则不会出现任何舍入错误。
答案 1 :(得分:12)
使用round()
:
$c = round($b - $a, 2);
注意:您也可以根据需要选择舍入模式。
修改:好的我没有得到sprintf()
正在做的事情number_format()
不是:
$c = number_format($b - $a, 2);
VS
$c = sprintf("%.2f", $b - $a);
答案 2 :(得分:4)
原生计算:
$a = 34.56;
$b = 34.55;
$c = $b - $a; // -0.010000000000005
按预期工作(!使用BC函数进行实数计算,问题适用于所有基于C的平台):
$a = '34.56';
$b = '34.55';
$c = bcsub($b, $a, 4); // -0.0100
答案 3 :(得分:3)
你遇到了其中一个浮点数陷阱;它们不能总是代表精确的小数部分。如果你想要精确的十进制值,你最好使用整数然后除以你想要的精度。
例如,如果您在花车中进行计算,代表美元(或您最喜欢的货币),您可能希望以整数美分进行计算。
答案 4 :(得分:3)
只需使用bcmath库,您就可以非常巧妙地回避所有这些问题。
请记住阅读文档,并注意是否将参数作为字符串或数值数据类型传递。
答案 5 :(得分:3)
我最近在使用浮点数进行计算时遇到了这个问题。例如,我有2个浮点数,当减去并格式化时,值为-0.00。
$floatOne = 267.58;
$floatTwo = 267.58;
$result = number_format($floatOne - floatTwo, 2);
print $result; //printed a string -0.00
我做的是:
$result = abs($floatOne - $floatTwo);// Made the number positive
print money_format('%i', $result); // printed the desired precision 0.00
在我的解决方案中,我知道floatOne永远不会小于floatTwo。 仅当系统具有strfmon功能时,才会定义money_format功能,而Windows则不会。
答案 6 :(得分:1)
如果仍然有人到达此页面时出现类似问题,其中浮点数减法会导致错误或奇怪的值。 我想用更多细节来解释这个问题。罪魁祸首是浮点数。 不同的操作系统和不同版本的编程语言可以表现不同。
为了说明问题,我将通过下面的简单示例解释原因。
它与PHP没有直接关系,也不是bug。 但是,每个程序员都应该意识到这个问题。
这个问题在20年前甚至夺走了许多人的生命。
1991年2月25日,MIM-104爱国者导弹电池的浮动数计算问题使得它无法拦截沙特阿拉伯达兰的一枚来自飞毛腿的导弹,导致28名士兵死于美国陆军第14号军需官支队。
但为什么会这样呢?
原因是浮点值表示有限的精度。所以,价值可能 任何处理后都没有相同的字符串表示。它也是 包括在脚本中直接写入浮点值 在没有任何数学运算的情况下打印它。
只是一个简单的例子:
$a = '36';
$b = '-35.99';
echo ($a + $b);
你会期望它打印0.01,对吗? 但它会打印一个非常奇怪的答案,如0.009999999999998
与其他数字一样,浮点数double或float作为0和1的字符串存储在内存中。浮点与整数的不同之处在于我们在想要查看它们时如何解释0和1。它们的存储方式有很多标准。
浮点数通常作为符号位,指数字段和有效数字或尾数从左到右打包到计算机数据中....
由于空间不足,十进制数字没有很好地用二进制表示。所以,你不能完全表达1/3,就像它的0.3333333 ......,对吧?为什么我们不能将二进制浮点数表示为0.01也是出于同样的原因。 1/100为0.00000010100011110101110000 .....重复10100011110101110000。
如果0.01以二进制格式保存为01000111101011100001010的简化和系统截断形式,当它被转换回十进制时,它将被读取为0.0099999 ....取决于系统(64位计算机将提供比32位)。在这种情况下,操作系统决定是否按照它看到的方式打印它,或者如何以更人性化的方式进行打印。因此,它依赖于机器的方式来表示它。但它可以用不同的方法在语言层面进行保护。
如果格式化结果,则echo number_format(0.009999999999998,2);它将打印0.01。
这是因为在这种情况下,您将指示如何阅读以及您需要的精确度。