【问题标题】:PHP: get number of decimal digitsPHP:获取小数位数
【发布时间】:2011-01-26 16:03:56
【问题描述】:

有没有一种直接的方法来确定 PHP 中 a(n) 整数/双精度值的小数位数? (即不使用explode

【问题讨论】:

    标签: php decimal


    【解决方案1】:

    您可以尝试将其转换为 int,从您的数字中减去它,然后计算剩下的内容。

    【讨论】:

    • 在我看来非常好的答案,如果我是对的,你一定是这个意思:echo strlen($num-(int)$num)-2;
    • $decimals = ( (int) $num != $num ) ? (strlen($num) - strpos($num, '.')) - 1 : 0; 也适用于负数。
    • @EvanMattson 不适用于溢出的非常大的浮点数。
    • 我在 Dart 中做这个,这不起作用,因为浮点减法不精确,例如做(3.005 - 3).toString().length 得到了 20。我希望在任何编程语言中都有这种行为?
    【解决方案2】:

    类似:

    <?php
    
    $floatNum = "120.340304";
    $length = strlen($floatNum);
    
    $pos = strpos($floatNum, "."); // zero-based counting.
    
    $num_of_dec_places = ($length - $pos) - 1; // -1 to compensate for the zero-based count in strpos()
    
    ?>
    

    这是程序性的,笨拙的,我不建议在生产代码中使用它。但它应该让你开始。

    【讨论】:

    • 我尝试将样本值更改为整数值,结果显示为“2”。我想要实现的是一个过程,如果数字是整数,则返回 0,否则返回小数位数
    • 当您说“整数”时,您的整数的格式是“10.00”还是“10”?
    • 它的值为 10。我期待不同的格式,例如 10、10.00、10.000。根据格式,我必须知道使用的小数位数
    【解决方案3】:
    $str = "1.23444";
    print strlen(substr(strrchr($str, "."), 1));
    

    【讨论】:

    • 这不适用于在表示为字符串时转换为科学记数法的极大或极小的浮点数。
    • 一个例子:var_dump((string)(0.00000000000012)); 输出string(7) "1.2E-13"
    • @GordonM 你可以用 number_format 解决这个问题:$str = rtrim(number_format($value, 14 - log10($value)), '0');。 14是基于PHP中浮点数的最大精度;如果您首先对浮点数进行一些数学运算,则可能需要减少一点(特别是如果它是通过减去两个较大的数字获得的)。
    • 如果使用大量数字,只减去 1 而不是获取子字符串可能更有效:strlen(strrchr($str, "."))-1;
    • @GordonM 您的解决方案是天才。但是取决于 php 在未来某个时候或在相当不寻常的系统上不会改变精度
    【解决方案4】:
    $decnumber = strlen(strstr($yourstr,'.'))-1
    

    【讨论】:

      【解决方案5】:
      function numberOfDecimals($value)
      {
          if ((int)$value == $value)
          {
              return 0;
          }
          else if (! is_numeric($value))
          {
              // throw new Exception('numberOfDecimals: ' . $value . ' is not a number!');
              return false;
          }
      
          return strlen($value) - strrpos($value, '.') - 1;
      }
      
      
      /* test and proof */
      
      function test($value)
      {
          printf("Testing [%s] : %d decimals\n", $value, numberOfDecimals($value));
      }
      
      foreach(array(1, 1.1, 1.22, 123.456, 0, 1.0, '1.0', 'not a number') as $value)
      {
          test($value);
      }
      

      输出:

      Testing [1] : 0 decimals
      Testing [1.1] : 1 decimals
      Testing [1.22] : 2 decimals
      Testing [123.456] : 3 decimals
      Testing [0] : 0 decimals
      Testing [1] : 0 decimals
      Testing [1.0] : 0 decimals
      Testing [not a number] : 0 decimals
      

      【讨论】:

      • 请注意,php 将源中的文字 1.0 解释为整数,因此在转换为字符串时它没有小数。 (即使您在声明时将其转换为浮动,所以 $variable = (float)1.0; 不起作用
      • 这不适用于非常小或非常大的浮点数,它们在转换为字符串时以科学计数法输出。 var_dump (strval (1/1000000));
      • 这在国际环境中不起作用,但稍作改动即可:$localconv = localeconv(); return strlen($value) - strrpos($value, $localconv['decimal_point']) - 1;
      【解决方案6】:

      我使用以下内容来确定返回值是否有小数(实际的十进制值,而不仅仅是格式化为显示小数,如 100.00):

      if($mynum - floor($mynum)>0) {has decimals;} else {no decimals;} 
      

      【讨论】:

        【解决方案7】:

        这个怎么样?

        $iDecimals = strlen($sFull%1);
        

        【讨论】:

        • $sFull = 3.1459287; echo $sFull%1; 结果:0。所以:没有。
        【解决方案8】:
        <?php
        
        test(0);
        test(1);
        test(1.234567890);
        test(-123.14);
        test(1234567890);
        test(12345.67890);
        
        function test($f) {
            echo "f = $f\n";
            echo "i = ".getIntCount($f)."\n";
            echo "d = ".getDecCount($f)."\n";
            echo "\n";
        }
        
        function getIntCount($f) {
            if ($f === 0) {
                return 1;
            } elseif ($f < 0) {
                return getIntCount(-$f);
            } else {
                return floor(log10(floor($f))) + 1;
            }
        }
        
        function getDecCount($f) {
            $num = 0;
            while (true) {
                if ((string)$f === (string)round($f)) {
                    break;
                }
                if (is_infinite($f)) {
                    break;
                }
        
                $f *= 10;
                $num++;
            }
            return $num;
        }
        

        输出:

        f = 0
        i = 1
        d = 0
        
        f = 1
        i = 1
        d = 0
        
        f = 1.23456789
        i = 1
        d = 8
        
        f = -123.14
        i = 3
        d = 2
        
        f = 1234567890
        i = 10
        d = 0
        
        f = 12345.6789
        i = 5
        d = 4
        

        【讨论】:

          【解决方案9】:
          $value = 182.949;
          
          $count = strlen(abs($value - floor($value))) -2; //0.949 minus 2 places (0.)
          

          【讨论】:

          • 我在这个测试中遇到了 php 精度问题,返回 0.94900000000001
          【解决方案10】:

          这是一个考虑尾随零的函数:

          function get_precision($value) {
              if (!is_numeric($value)) { return false; }
              $decimal = $value - floor($value); //get the decimal portion of the number
              if ($decimal == 0) { return 0; } //if it's a whole number
              $precision = strlen($decimal) - 2; //-2 to account for "0."
              return $precision; 
          }
          

          【讨论】:

          • 这很棒,但有一种更简单的方法: is_numeric($value) ? max(strlen(strrchr(abs($value), ".")) - 1, 0) : FALSE;
          【解决方案11】:

          内部

          整数没有小数位,所以答案总是零。

          双/浮动

          双数或浮点数是近似值。所以它们没有定义的小数位数。

          一个小例子:

          $number = 12.00000000012;
          $frac = $number - (int)$number;
          
          var_dump($number);
          var_dump($frac);
          

          输出:

          float(12.00000000012)
          float(1.2000000992884E-10)
          

          您可以在这里看到两个问题,第二个数字是使用科学表示法,它不完全是 1.2E-10。

          字符串

          对于包含整数/浮点数的字符串,您可以搜索小数点:

          $string = '12.00000000012';
          $delimiterPosition = strrpos($string, '.');
          var_dump(
            $delimiterPosition === FALSE ? 0 : strlen($string) - 1 - $delimiterPosition
          );
          

          输出:

          int(11)
          

          【讨论】:

            【解决方案12】:

            我需要一个适用于各种数字格式的解决方案,并提出了以下算法:

            // Count the number of decimal places
            $current = $value - floor($value);
            for ($decimals = 0; ceil($current); $decimals++) {
                $current = ($value * pow(10, $decimals + 1)) - floor($value * pow(10, $decimals + 1));
            }
            
            // Count the total number of digits (includes decimal places)
            $current = floor($value);
            for ($digits = $decimals; $current; $digits++) {
                $current = floor($current / 10);
            }
            

            结果:

            input:    1
            decimals: 0
            digits:   1
            
            input:    100
            decimals: 0
            digits:   3
            
            input:    0.04
            decimals: 2
            digits:   2
            
            input:    10.004
            decimals: 3
            digits:   5
            
            input:    10.0000001
            decimals: 7
            digits:   9
            
            input:    1.2000000992884E-10
            decimals: 24
            digits:   24
            
            input:    1.2000000992884e6
            decimals: 7
            digits:   14
            

            【讨论】:

              【解决方案13】:

              首先,我使用strpos 函数找到了小数点的位置,并将strpos 的位置值增加1 以跳过小数位。

              其次,我从 point1 得到的值中减去了整个字符串的长度。

              第三,我使用substr函数来获取小数点后的所有数字。

              第四,我使用strlen函数来获取小数点后字符串的长度。

              这是执行上述步骤的代码:

                   <?php
                      $str="98.6754332";
                      echo $str;
                      echo "<br/>";
                      echo substr( $str, -(strlen($str)-(strpos($str, '.')+1)) );
                      echo "<br/>";
                      echo strlen( substr( $str, -(strlen($str)-(strpos($str, '.')+1))) );
                  ?>
              

              【讨论】:

              • 如果您能解释一下您的解决方案是如何工作的,将会很有帮助。
              • @Stibu hi..我已经更新了答案,如果您有任何疑问,请检查并告诉我。
              • 您添加了一些文字,这绝对是个好主意。由于我不熟悉PHP,我无法判断您的帖子的内容。我试图清理格式并改写你的最后一句话。如果您不同意这些更改,请随时将其删除或重新编辑。
              【解决方案14】:

              解决方案

              $num = "12.1234555";
              print strlen(preg_replace("/.*\./", "", $num)); // 7
              

              说明

              模式.*\.表示小数点前的所有字符都带有它。

              在这种情况下,它是包含三个字符的字符串:12.

              preg_replace 函数将这些缓存的字符转换为空字符串""(第二个参数)。

              在这种情况下,我们得到这个字符串:1234555

              strlen函数统计保留字符串的字符数。

              【讨论】:

              • 也许这个答案可以通过解释你的 OP 代码来改进
              • 这个用例不会处理没有小数的值。这是正确的实现受限替换(关闭全局替换):strlen(preg_replace('/[\d]+[\.]?/', '', $finalValue, 1))
              【解决方案15】:

              您应该始终注意不同的语言环境。欧洲语言环境使用逗号作为千位分隔符,因此接受的答案不起作用。修改后的解决方案见下文:

               function countDecimalsUsingStrchr($stringValue){
                      $locale_info = localeconv();
                      return strlen(substr(strrchr($stringValue, $locale_info['decimal_point']), 1));
                  }
              

              localeconv

              【讨论】:

                【解决方案16】:

                如果为了其他开发者的利益而想要可读性,语言环境安全,请使用:

                function countDecimalPlacesUsingStrrpos($stringValue){
                    $locale_info = localeconv();
                    $pos = strrpos($stringValue, $locale_info['decimal_point']);
                    if ($pos !== false) {
                        return strlen($stringValue) - ($pos + 1);
                    }
                    return 0;
                }
                

                localeconv

                【讨论】:

                • 我不知道我这样做了。我批准了。那天晚些时候,我查看了这个,发现没有应用编辑,所以我自己更改了它。不知道发生了什么。
                • 嗯,它仍然不存在,所以我要重新提交它。该函数在没有前导数字(例如 .25 或 .3333 )的浮点数上无法正常工作。 (相对于 0.25 或 0.3333)。这是因为 $pos 为 0,其计算结果为 false。在这种情况下,0 正是正确的答案,因此我们需要对 $pos !== false 进行类型精明的检查。如果十进制字符根本没有找到,strrpos 将返回 false,但如果它是字符串中的第一个字符,则返回 0。
                • 谢谢菲尔,我运行了一些单元测试,它现在可以处理没有前面数字的值,例如.34
                【解决方案17】:

                这适用于任何数字,即使是科学计数法,精度高达小数点后 100 位。

                $float = 0.0000005;
                
                $working = number_format($float,100);
                $working = rtrim($working,"0");
                $working = explode(".",$working);
                $working = $working[1];
                
                $decmial_places = strlen($working);
                

                结果:

                7
                

                冗长但没有复杂的条件。

                【讨论】:

                • 其实根本不行。 demo
                【解决方案18】:

                更少的代码:

                $str = "1.1234567";
                echo (int) strpos(strrev($str), ".");
                

                【讨论】:

                • 聪明。仅供参考,如果数字没有小数点,strpos 将返回 false 而不是 0
                • @andrewtweber 已更新 :)
                猜你喜欢
                • 2022-01-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-05-30
                • 1970-01-01
                • 2015-12-26
                • 2020-04-15
                • 1970-01-01
                相关资源
                最近更新 更多