【问题标题】:Delete digits after two decimal points, without rounding the value删除小数点后两位数,不四舍五入
【发布时间】:2012-03-30 13:32:41
【问题描述】:

我在这样的 php 变量中有值

$var='2.500000550';
echo $var

我想要的是删除 2 位数字后的所有小数点。

现在变量的值将是

$var='2.50';
echo $var

记住这个值来自mysql数据库

但是当我使用round php function 时,我得到了四舍五入,但我不需要四舍五入,我只需要简单地删除小数点后 2 位之后的所有数字。

我累了,flot() 和很多其他选项都没有成功。

谢谢

【问题讨论】:

  • 你试过 number_format 吗?
  • 它没有明确记录,但 number_format 轮。

标签: php function rounding


【解决方案1】:

TL;DR:

PHP 原生函数 bcdiv 似乎准确地完成了所需的工作,而且做得很好。

要简单地“截断”一个数字,bcdiv($var, 1, 2); 其中 2 是要保留的小数位数(1 是分母 - 将数字除以 1 可以简单地将原始数字截断到所需的小数位)

完整答案(历史记录)

事实证明,这比人们想象的更难以捉摸。

在这个答案被(错误地)点赞之后,我注意到即使是 sprintf 也会圆整。

我没有删除这个答案,而是将其转化为对每个提议的解决方案的更强有力的解释/讨论。

number_format - 不正确。 (回合)
尝试使用number format

$var = number_format($var, 2, '.', '');  // Last two parameters are optional
echo $var;
// Outputs 2.50

如果您希望它是一个数字,那么只需将其类型转换为浮点数:

$var = (float)number_format($var, 2, '.', '');

注意: 正如 cmets 中所指出的,这实际上是对数字进行四舍五入

sprintf - 不正确。 (sprintf 也是四舍五入)
如果不四舍五入很重要,那么根据下面的答案,使用sprintf

$var = sprintf("%01.2f", $var);

地板 - 不完全是! (地板舍入负数)

floor,通过一些数学运算,将接近于做你想做的事:

floor(2.56789 * 100) / 100; // 2.56

其中 100 代表您想要的精度。如果你想要三位数,那么:

floor(2.56789 * 1000) / 1000; // 2.567

但是,这对负数有问题。负数仍会四舍五入,而不是截断:

floor(-2.56789 * 100) / 100; // -2.57

“旧”正确答案:利用地板的功能

所以一个完全健壮的解决方案需要一个函数:

function truncate_number( $number, $precision = 2) {
    // Zero causes issues, and no need to truncate
    if ( 0 == (int)$number ) {
        return $number;
    }
    // Are we negative?
    $negative = $number / abs($number);
    // Cast the number to a positive to solve rounding
    $number = abs($number);
    // Calculate precision number for dividing / multiplying
    $precision = pow(10, $precision);
    // Run the math, re-applying the negative value to ensure returns correctly negative / positive
    return floor( $number * $precision ) / $precision * $negative;
}

上述函数的结果:

echo truncate_number(2.56789, 1); // 2.5
echo truncate_number(2.56789);    // 2.56
echo truncate_number(2.56789, 3); // 2.567

echo truncate_number(-2.56789, 1); // -2.5
echo truncate_number(-2.56789);    // -2.56
echo truncate_number(-2.56789, 3); // -2.567

新的正确答案

使用PHP原生函数bcdiv

echo bcdiv(2.56789, 1, 1);  // 2.5
echo bcdiv(2.56789, 1, 2);  // 2.56
echo bcdiv(2.56789, 1, 3);  // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 2); // -2.56
echo bcdiv(-2.56789, 1, 3); // -2.567

【讨论】:

  • 应该提到 number_format 返回的是字符串而不是数字。
  • @MuhammadAtif - 是的,这不是这篇文章中的正确答案。正确答案是bcdiv
  • 顺便说一句,如果您只需要删除数字,则首选 bcadd($num_FLO, 0, $prec_INT),因为它比 div 或 mul 操作更快)
  • @Bill_VA - 感谢您的评论。实际上,我的代码是正确的(和你的一样),而我的代码遵循已知的“防御性”编码模式Yoda Conditions。如果您忘记了 your 代码中的= 符号之一,您会无意中将0 分配给$number 变量。如果您忘记了 my 代码中的 = 符号之一,则会出现错误,并且 PHP 将无法运行。
  • 到目前为止,绝对是网络上最好的答案 typeof() 说它也是双精度数!
【解决方案2】:
floor(2.500000550 * 100) / 100;

这应该可以完成您的任务...

【讨论】:

  • 这是最简单的方法。 number_format 仍然对结果进行四舍五入。
  • 这应该被标记为答案恕我直言,@air。所有其他答案在截断之前四舍五入,这样四舍五入仅在导致最后一个所需的(在本例中为第二个)小数位增加时才明显。该解决方案通过有效地将小数点向右移动两位(乘以 100)、截断(使用下限)、然后将其向左移动 2 位(除以 100)来避免这种情况。天才在于简单。
  • @Sepster - 实际上,这有舍入负数的问题。我已经改进了我的答案以解决这种情况。
  • 好皮卡,@cale_b!
  • 这也可以很容易地变成一个函数,你可以输入你想看到的小数位数。
【解决方案3】:

您正在请求一个返回"2.50" 而不是2.5 的函数,所以您在这里谈论的不是算术,而是字符串操作。那么preg_replace就是你的朋友:

$truncatedVar = preg_replace('/\.(\d{2}).*/', '.$1', $var);

// "2.500000050" -> "2.50", "2.509" -> "2.50", "-2.509" -> "2.50", "2.5" -> "2.5"

如果你想用算术来做,只需使用:

$truncatedVar = round($var * 100) / 100);

// "2.500000050" -> "2.5", "2.599" -> "2.59", "-2.599" -> "2.59"

【讨论】:

  • 不适用于二进制系统中周期性的数字,试试吧,例如 'intval(2.092484 * 1000000) / 1000000' => 你会得到 '2.092483' ,但是你的字符串与 preg_replace效果很好,从我这里开始,谢谢
  • @FantomX1 你说得对。如果我想成为吹毛求疵的人,我会说 OP 要求提供两位数和'intval(2.092484 * 100) / 100' is 2.09`,但我认为使用round 而不是intval 应该会使这更加防弹。谢谢!
  • 有两位小数的好点,虽然我个人需要 6,但舍入删除了周期数无限序列,这是真的,但是当我将数据与远程系统进行比较时,你并不总是想像我一样舍入,其中 mysql 列完全按照您的字符串替换,只是从我想要始终返回 2.09 的特定序数中截断,无论它是 2.094 还是 2.096,因此 round 对我没有用,但是 preg 替换有效
【解决方案4】:

试试number_format:

echo number_format('2.50000050', 2); // 2.50

【讨论】:

  • 这是四舍五入,然后截断。因此,如果输入数字是 2.509,那么上面将返回 2.51,而不是 2.50。所以不回答明确声明“不圆”的问题
  • 还有他问怎么删除,你还是保留分数
【解决方案5】:

number_format 对数字进行四舍五入

php > echo number_format(128.20512820513, 2)."\n";
128.21

我用 preg_replace 来真正的剪断字符串

php > echo preg_replace('/(\.\d\d).*/', '$1', 128.20512820513)."\n";
128.20

【讨论】:

    【解决方案6】:

    有人在这里发布了关于

    地板(2.500000550 * 100) / 100;

    function cutAfterDot($number, $afterDot = 2){
    $a = $number * pow(10, $afterDot);
    $b = floor($a);
    $c = pow(10, $afterDot);
    echo "a $a, b $b, c $c<br/>";
    return $b/$c ;
    }
    echo cutAfterDot(2.05,2);
    
    a 205, b 204, c 100
    2.04
    

    所以不要以原始形式使用它... 但是,如果您添加一点 epsilon...

    function cutAfterDot($number, $afterDot = 2){
            return floor($number * pow(10, $afterDot) + 0.00001) / pow(10, $afterDot);
        }
    

    有效!

    【讨论】:

    【解决方案7】:

    使用 PHP 原生函数 bcdiv

    示例:

    echo bcdiv(3.22871, 1, 1);  // 3.2
    echo bcdiv(3.22871, 1, 2);  // 3.22
    echo bcdiv(3.22871, 1, 3);  // 3.228
    echo bcdiv(-3.22871, 1, 1); // -3.2
    echo bcdiv(-3.22871, 1, 2); // -3.22
    

    对于您的情况:

    $var='2.500000550';
    echo $var
    echo bcdiv($var, 1, 2);  // 2.50
    

    【讨论】:

      【解决方案8】:

      使用sprintf

      sprintf("%01.2f", $var);
      

      【讨论】:

      • 这是四舍五入,然后截断。所以如果$var == 2.509 那么上面将返回 2.51,而不是 2.50。所以不回答明确说明“不圆”的问题。
      【解决方案9】:

      以下是(我认为是 - 如果不是,请纠正我)一个强大的数学*解决方案,主要基于此处其他几个回答者的信息,以及来自我的少量信息

      (*这并不是说 Liphtier's regex-based answer 有什么问题——只是我可以看到纯粹主义者想要避免正则表达式来解决可以说是数学问题的问题。)

      • sprintf()number_format()(显然还有round())都在执行舍入操作,因此不适用于问题中请求的非舍入截断(至少不是它们自己)。
      • 代替开箱即用的功能,看似最优雅的解决方案是Sujit Agarwal's answer
      • 但是由于浮点数的存储方式,我们需要使用 epsilon - 正如David Constantine's answer 中所指出的那样(他还通过使用pow() 使先前的解决方案更通用,以根据指定的精度)。
      • 但是,正如cale_b's answer 中所指出的,任何使用floor()(或可能是ceil())都可能会在不使用abs() 的情况下对负片产生意想不到的结果。
      • 我要添加的值是:
        • 如果在abs() 上使用除法来获得否定因子,我们需要考虑输入为 0 时的特殊情况。
        • 我们应该动态创建 epsilon;静态硬编码 epsilon 可能太小或太大,具体取决于所需的精度。我没有在其他答案中看到这个问题。

      我使用的代码是:

      public static function truncate_decimal($number, $leavePlaces = 2)
      {
          if ($number == 0) return 0;
          $negate = $number / abs($number);
          $shiftFactor = pow(10, $leavePlaces);
          $epsilon = pow(10, -1 * $leavePlaces);
          return floor(abs($number) * $shiftFactor + $epsilon) / $shiftFactor * $negate;
      }
      

      【讨论】:

        【解决方案10】:

        已经有很多可能的解决方案了,我只想添加一个我想出的来解决我的问题。

        function truncate_decimals($number, $decimals=2)
        {
          $factor = pow(10,$decimals); 
          $val = intval($number*$factor)/$factor;
          return $val;
        }
        
        
        truncate_decimals(199.9349,2);
        // 199.93
        

        【讨论】:

        • 刚刚试了一下,它给了我,这似乎是正确的。 truncate_decimals(10056468765.254564) => 10056468765.25
        • 我会调查并删除我之前的评论。如果我找到重现的步骤,请在此处发布。
        【解决方案11】:

        所有使用 number_format 的解决方案都是错误的,因为 number_format 执行舍入。

        下面的函数应该适用于所有数字,你可以为那些使用','的国家指定小数分隔符。

        function truncate_decimal($number, $truncate_decimal_length = 2, $decimal_character = '.', $thousands_character = '') {
        
        $number = explode($decimal_character, $number);
        $number[1] = substr($number[1], 0, $truncate_decimal_length);
        $number_truncated = implode($decimal_character, $number);
        return number_format($number_truncated, $truncate_decimal_length, $decimal_character, $thousands_character);
        
        }
        

        【讨论】:

          【解决方案12】:

          一个简单的函数是“如果大于 0 层,否则 ceil”,在执行此操作时使用乘数将其临时提高到小数点以上:

          function trim_num($num_in, $dec_places = 2) {
              $multiplier = pow(10, $dec_places); // 10, 100, 1000, etc
              if ($num_in > 0) {
                  $num_out = floor($num_in * $multiplier) / $multiplier;
              } else {
                  $num_out = ceil($num_in * $multiplier) / $multiplier;
              }
              return $num_out;
          }
          

          【讨论】:

            【解决方案13】:
            $num = 118.74999669307;
            $cut = substr($num, 0, ((strpos($num, '.')+1)+2));
            // Cut the string from first character to a length of 2 past the decimal.
            // substr(cut what, start, ( (find position of decimal)+decimal itself)+spaces after decimal) )
            echo $cut; 
            

            【讨论】:

              【解决方案14】:

              地板 - 不完全是! (地板舍入负数)

              cale_b 答案的可能解决方案。

              static public function rateFloor($rate, $decimals)
              {
              
                  $div = "1" . str_repeat("0", $decimals);
              
                  if ($rate > 0) {
                      return floor($rate * $div) / $div;
                  }
              
                  $return = floor(abs($rate) * $div) / $div;
              
                  return -($return);
              
              }
              

              static public function rateCeil($rate, $decimals)
              {
              
                  $div = "1" . str_repeat("0", $decimals);
              
                  if ($rate > 0) {
                      return ceil($rate * $div) / $div;
                  }
              
                  $return = ceil(abs($rate) * $div) / $div;
              
                  return -($return);
              
              }
              

              正面

              费率:0.00302471

              楼层:0.00302400

              上限:0.00302500

              否定

              比率:-0.00302471

              楼层:-0.00302400

              上限:-0.00302500

              【讨论】:

                【解决方案15】:

                如果你不想对数字进行四舍五入,但你想删除小数位,你可以使用“substr”方法

                substr(string, start, length);
                substr(4.96, 0, -1);
                

                【讨论】:

                • 这不适用于“2.500000550”作为值。根据您的解决方案,您将获得“2.50000055”作为结果。
                • 你必须增加长度,substr(2.500000550, 0, -6);那么你会得到'2.50',
                • 数据来自mysql数据库,所以应该是动态的
                猜你喜欢
                • 1970-01-01
                • 2022-01-02
                • 2017-03-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-06-11
                • 1970-01-01
                相关资源
                最近更新 更多