我一直在努力解决PHP的ceil()函数给我的结果有点错误的问题-考虑以下情况:
$num = 2.7*3; //float(8.1)
$num*=10; //float(81)
$num = ceil($num); //82, but shouldn't this be 81??
$num/=10; //float(8.2)
我有一个数字,它可以有任意小数位,我需要它四舍五入到小数点后一位。即8.1应该是8.1,8.154应该是8.2,8应该保留为8。
我是如何得到这个数字的,乘以10,然后除以10,但正如你所看到的,在某些情况下,我得到了一个额外的。1。
谁能告诉我为什么会发生这种情况,以及如何解决它?
任何帮助都非常感谢
编辑:将*=10改为+=10:S
编辑2:我没有明确提到这一点,但我需要小数点总是四舍五入,而不是向下-这个答案是最接近目前为止:
rtrim(rtrim(sprintf('%.1f', $num), '0'), '.');
然而,当我需要3.9时,将3.84舍入到3.8。对不起,这不是更清楚:(
最后的编辑:
我最后做的是:
$num = 2.7*3; //float(8.1)
$num*=10; //float(81)
$num = ceil(round($num, 2)); //81 :)
$num/=10; //float(8.1)
这很可能是由于浮点错误。
- http://support.microsoft.com/kb/42980
- http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html
- http://joshblog.net/2007/01/30/flash-floating-point-number-errors/
- http://en.wikipedia.org/wiki/Floating_point
你可以试试这个程序。
<?php
$num = 2.7*3;
echo rtrim(rtrim(sprintf('%.1f', $num), '0'), '.');
浮动可以是一个变化无常的东西。并不是所有的实数都可以用有限的二进制位表示。
事实证明,0.7的小数部分就是这些数字之一(结果是0.10,后面有一个无限重复的"1100")。最后得到的数字略高于0.7,所以当你乘以10时,你得到的个位数略高于7。
你能做的是做一个完整性检查。用浮点数减去它的整数形式。如果结果值小于0.0001,则将其视为内部舍入误差并保持原样。如果结果大于0.0001,则正常应用ceil()。
Edit:如果你在windows上,你可以做一个有趣的例子来显示这一点,那就是打开内置的计算器应用程序。输入"4",然后应用平方根函数(x^y,其中y=0.5)。您将看到它正确地显示"2"。现在,从它减去2,你会发现结果不是0。这是由于试图计算4的平方根时的内部舍入错误造成的。在前面显示数字2时,它知道那些非常远的尾数可能是舍入错误,但是当剩下这些数字时,它就有点困惑了。
(在有人问我这个问题之前,我知道这是过度简化的,但我认为这是一个不错的例子。)
将您的号码转换为字符串并将字符串设置为上限
function roundUp($number, $decimalPlaces){
$multi = pow(10, $decimalPlaces);
$nrAsStr = ($number * $multi) . "";
return ceil($nrAsStr) / $multi;
}
问题是浮点数很少是您所期望的。你的2.7*3可能会得到类似于81.0000000000000000001的东西,其中ceil()的值高达82。对于这类事情,您必须用一些精确检查来包装您的天花板/圆/地板调用,以处理这些额外的微观差异。
用%f
代替%.1f
。
echo rtrim(rtrim(sprintf('%f', $num), '0'), '.');
为什么不试试呢:
$num = 2.7*3;
$num *= 100;
$num = floor($num);
$num /= 10;
$num = ceil($num);
$num /= 10;