PHP舍入错误

我在我的linux服务器上使用PHP 5.2.13。在舍入数字时,我遇到了奇怪的错误。这是我的测试用例:
<?php
echo "        " . round(1.505, 2) . "n";
echo "       " . round(11.505, 2) . "n";
echo "      " . round(111.505, 2) . "n";
echo "     " . round(1111.505, 2) . "n";
echo "    " . round(11111.505, 2) . "n";
echo "   " . round(111111.505, 2) . "n";
echo "  " . round(1111111.505, 2) . "n";
echo " " . round(11111111.505, 2) . "n";
echo "" . round(111111111.505, 2) . "n";
这是结果:
        1.51
       11.51
      111.51
     1111.51
    11111.51
   111111.51
  1111111.5
 11111111.51
111111111.51
谁知道是什么原因造成的?我无法更新PHP,因为它是共享服务器。     
已邀请:
这是因为数字1111111.505无法用浮点表示法精确表示。它最接近的是1111111.5049999999。所以最终发生的是它将代码中的数字转换为1111111.50499999999,然后进行舍入。其中结果为1111111.5。浮点数有问题,因为它们不能完全准确地表示很多看似简单的十进制数。例如。使用二进制浮点数无法准确表示数字0.1。使用Python,如果输入0.1,则返回0.10000000000001。加或减几个零。这就是某些语言(如.Net)提供“十进制”数据类型的原因,该数据类型能够表示特定范围内的所有十进制值和小数位数。十进制数据类型的缺点是速度较慢,每个数字需要更多空间来存储。     
如果仍然有人到达此页面时出现类似问题,其中浮点数减法会导致错误或奇怪的值。 我想用更多细节来解释这个问题。罪魁祸首是浮点数。 为了说明这个问题,我将用一个简单的例子解释为什么你可以从那里假设它为什么会影响舍入等。 它与PHP没有直接关系,也不是bug。 但是,每个程序员都应该意识到这个问题。 20年前,这个问题甚至夺走了许多人​​的生命。 1991年2月25日,MIM-104爱国者导弹电池的浮动数计算问题使得它无法拦截沙特阿拉伯达兰的一枚来自飞毛腿的导弹,导致美国陆军第14军需支队的28名士兵死亡。 但为什么会发生呢? 原因是浮点值表示有限的精度。所以,价值可能 任何处理后都没有相同的字符串表示。它也是 包括在脚本中直接写入浮点值 无需任何数学运算即可打印。 只是一个简单的例子:
$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。 这是因为在这种情况下,您将指示如何阅读以及您需要的精度。 参考文献:1,2,3,4,5     
你需要升级wetwaer - 而不是PHP版本。   回声“”。回合(1.505,2)。 “ n” 个; 你似乎认为你要求PHP返回1.505的舍入值 - 但它实际上要返回1.505的二进制版本的舍入版本的十进制版本 尝试在此处输入数字并查看二进制表示。     
对我而言,就像你遇到了使用花车造成的准确性问题一样。浮动不保证完全准确,您可能会发现此问题出现在一个系统上,而不是另一个系统上。 如果您真的关心具有任意浮点数的精度,请使用bcmath或gmp(如果有),但是如果使用bcmath,则需要创建bcround()函数。我发现的唯一一个实际工作的是在php.net bcscale页面的评论中发布的:
function bcround($number, $scale=0) {
        $fix = "5";
        for ($i=0;$i<$scale;$i++) $fix="0$fix";
        $number = bcadd($number, "0.$fix", $scale+1);
        return    bcdiv($number, "1.0",    $scale);
}
    
@Shabbyrobe:你的功能错了:尝试用2:44069.3445的比例来舍入这个数字 它应该是44069.35,但默认是php round() - 你的函数返回44069.34 php.net成员的工作代码:
function mround($number, $precision=0) {

$precision = ($precision == 0 ? 1 : $precision);   
$pow = pow(10, $precision);

$ceil = ceil($number * $pow)/$pow;
$floor = floor($number * $pow)/$pow;

$pow = pow(10, $precision+1);

$diffCeil     = $pow*($ceil-$number);
$diffFloor     = $pow*($number-$floor)+($number < 0 ? -1 : 1);

if($diffCeil >= $diffFloor) return $floor;
else return $ceil;
}
    

要回复问题请先登录注册