【问题标题】:PHP How do I round down to two decimal places?PHP 如何舍入到小数点后两位?
【发布时间】:2012-08-29 23:12:07
【问题描述】:

我需要将 PHP 中的小数四舍五入到小数点后两位,以便:

49.955

变成……

49.95

我尝试了 number_format,但这只是将值四舍五入为 49.96。我不能使用 substr 因为数字可能更小(例如 7.950)。到目前为止,我一直无法找到答案。

非常感谢任何帮助。

【问题讨论】:

  • 但是圆形不是他需要的......

标签: php decimal rounding number-formatting


【解决方案1】:

这可以工作:floor($number * 100) / 100

【讨论】:

  • 地板(50.5) = 50 ==> 50/100 = 0.50
  • 但不是由于 floor 函数,而是奇怪的 PHP 数学。 9.7 * 100; // float 970(int) (9.7 * 100); // int 969
  • 不是奇怪的 PHP 数学,而是几乎所有编程语言中都存在的浮点数精度问题
  • floor($number / 100) * 100,不像这个例子
【解决方案2】:

不幸的是,之前的答案(包括接受的答案)都不适用于所有可能的输入。

1) sprintf('%1.'.$precision.'f', $val)

以 2 的精度失败:14.239 应该返回 14.23(但在这种情况下返回 14.24)。

2) floatval(substr($val, 0, strpos($val, '.') + $precision + 1))

以 0 的精度失败:14 应该返回 14(但在这种情况下返回 1)

3)substr($val, 0, strrpos($val, '.', 0) + (1 + $precision))

以 0 的精度失败:-1 应该返回 -1(但在这种情况下返回 '-')

4) floor($val * pow(10, $precision)) / pow(10, $precision)

虽然我广泛使用了这个,但我最近发现了它的一个缺陷;对于某些值,它也失败了。精度为 2 : 2.05 应该返回 2.05 (但在这种情况下返回 2.04 !!)

到目前为止,不幸的是,通过所有测试的唯一方法是使用字符串操作。我基于rationalboss one的解决方案是:

function floorDec($val, $precision = 2) {
    if ($precision < 0) { $precision = 0; }
    $numPointPosition = intval(strpos($val, '.'));
    if ($numPointPosition === 0) { //$val is an integer
        return $val;
    }
    return floatval(substr($val, 0, $numPointPosition + $precision + 1));
}

此函数适用于正数和负数,以及所需的任何精度。

【讨论】:

  • 嘿,我意识到这是很久以前的事了,但是如果 $val 是像 -3E-15 这样的科学计数法中的浮点数,那么即使您的解决方案也会中断
  • @zedling 确实,floorDev 期待一个“经典”符号。我想你可以在$val 中检查'E'的'e',然后转换为字符串表示法。
【解决方案3】:

这是一个很好的函数,它可以在不使用字符串函数的情况下完成任务:

<?php
function floorp($val, $precision)
{
    $mult = pow(10, $precision); // Can be cached in lookup table        
    return floor($val * $mult) / $mult;
}

print floorp(49.955, 2);
?>

另一种选择是在四舍五入前减去一个分数:

function floorp($val, $precision)
{
    $half = 0.5 / pow(10, $precision); // Can be cached in a lookup table
    return round($val - $half, $precision);
}

【讨论】:

  • 使用减法实际上适用于像 floorp(2.05, 2) 这样的数字(第一个函数不适用)。要正确处理负数,必须使用第三个 round() 参数:round($val - $half, $precision, $val
【解决方案4】:

我认为有一种很简单的方法可以实现这一点:

$rounded = bcdiv($val, 1, $precision);

这是working example。您需要安装 BCMath,但我认为它通常与 PHP 安装捆绑在一起。 :) Here is the documentation.

【讨论】:

    【解决方案5】:

    将您的输入乘以 100,将其 floor(),然后将结果除以 100。

    【讨论】:

      【解决方案6】:
      function roundDown($decimal, $precision)
      {
          $sign = $decimal > 0 ? 1 : -1;
          $base = pow(10, $precision);
          return floor(abs($decimal) * $base) / $base * $sign;
      }
      
      // Examples
      roundDown(49.955, 2);           // output: 49.95
      roundDown(-3.14159, 4);         // output: -3.1415
      roundDown(1000.000000019, 8);   // output: 1000.00000001
      

      此函数适用于任何精度的正负小数。

      此处的代码示例:http://codepad.org/1jzXjE5L

      【讨论】:

      • 请注意,这不适用于负数。它将“-0.57471264367815”变成“-1.42528”
      • 您的代码不起作用:$x = 1000.000000019; echo roundDown($x, 8); 输出 1000.90000264
      • @maxpovver 谢谢,修复了功能
      • @SvenKahn Thx,函数现在适用于负数
      【解决方案7】:

      你可以使用 bcdiv PHP 函数。

      bcdiv(49.955, 1, 2)
      

      【讨论】:

        【解决方案8】:

        试试round()函数

        像这样:round($num, 2, PHP_ROUND_HALF_DOWN);

        【讨论】:

        • OP 说他不想再围捕了。 Round() 向上取整为 0.5 或更大。
        • round($num, 2, PHP_ROUND_HALF_DOWN);?
        • 是的,我忘记了。但是您在原始答案中没有提到它:)(顺便说一句,我不是反对您的人)
        • @user1606963 PHP_ROUND_HALF_DOWN 仅准确地确定小数点后半部分会发生什么......它不会模仿在中点或更大处向下舍入的地板。例如,round(1.115, 2, PHP_ROUND_HALF_DOWN); 将向下舍入为 1.11,但 round(1.116, 2, PHP_ROUND_HALF_DOWN); 仍将向上舍入为 1.12,这不是预期的结果。关于乘以 100、下限和除以 100 的答案是我所知道的唯一一种实现四舍五入到 2 位小数同时始终向下舍入的方法。 (当然,除非转换为字符串并以这种方式进行操作)
        【解决方案9】:

        对于有需要的人,我使用了一个小技巧来克服数学函数故障,例如 floor 或 intval(9.7*100)=969 怪异。

        function floor_at_decimals($amount, $precision = 2)
        {
            $precise = pow(10, $precision);
            return floor(($amount * $precise) + 0.1) / $precise;
        }
        

        所以添加少量(无论如何都会被搁置)以某种方式解决了问题。

        【讨论】:

          【解决方案10】:
          function floorToPrecision($val, $precision = 2) {
                  return floor(round($val * pow(10, $precision), $precision)) / pow(10, $precision);
              }
          

          【讨论】:

          • 请在您的代码中添加一些解释 - 已经有多个其他答案,您应该解释是什么让您的代码比其他答案更好,甚至不同
          【解决方案11】:

          使用格式化输出

          sprintf("%1.2f",49.955) //49.95
          

          DEMO

          【讨论】:

            【解决方案12】:

            你可以使用:

            $num = 49.9555;
            echo substr($num, 0, strpos($num, '.') + 3);
            

            【讨论】:

              【解决方案13】:

              使用正则表达式的替代解决方案应该适用于所有正数或负数,整数或小数:

              if (preg_match('/^-?(\d+\.?\d{1,2})\d*$/', $originalValue, $matches)){
                  $roundedValue = $matches[1];
              } else {
                  throw new \Exception('Cannot round down properly '.$originalValue.' to two decimal places');
              }
              

              【讨论】:

                【解决方案14】:

                基于@huysentruitw 和@Alex 的回答,我想出了以下应该可以解决问题的函数。

                它通过了 Alex 的答案中给出的所有测试(为什么这是不可能的)并建立在 huysentruitw 的答案之上。

                function trim_number($number, $decimalPlaces) {
                    $delta = (0 <=> $number) * (0.5 / pow(10, $decimalPlaces));
                    $result = round($number + $delta, $decimalPlaces);
                    return $result ?: 0; // get rid of negative zero
                }
                

                关键是在原始数字符号的基础上加减delta,以支持修剪负数。 最后一件事是去掉负零 (-0),因为这可能是不受欢迎的行为。

                Link to "test" playground.

                编辑:bcdiv 似乎是要走的路。

                // round afterwards to cast 0.00 to 0
                // set $divider to 1 when no division is required
                round(bcdiv($number, $divider, $decimalPlaces), $decimalPlaces);
                

                【讨论】:

                  【解决方案15】:
                  sprintf("%1.2f",49.955) //49.95
                  

                  如果您需要在不四舍五入的情况下截断小数 - 这是不合适的,因为如果数字更多,例如 49.957,它将正常工作到最后 49.955它将四舍五入到 49.96
                  在我看来,Lght 对 floor 的回答是最普遍的。

                  【讨论】:

                    【解决方案16】:

                    你试过round($val,2) 吗?

                    有关round() 函数的更多信息

                    【讨论】:

                    • 还是返回49.96,他要的是49.95
                    • 尝试使用“mode”参数。 PHP_ROUND_HALF_UP、PHP_ROUND_HALF_DOWN、PHP_ROUND_HALF_EVEN 或 PHP_ROUND_HALF_ODD 之一。
                    • 否则你可以使用蛮力方法: floor(100*$val) / 100.
                    猜你喜欢
                    • 1970-01-01
                    • 2017-03-26
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-01-02
                    • 2013-12-25
                    • 1970-01-01
                    • 2022-01-12
                    相关资源
                    最近更新 更多