PHP ceil给出错误的结果,如果输入是一个没有小数的浮点数


PHP ceil gives wrong results if input is a float with no decimal

我一直在努力解决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;