且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

将浮点数转换为纯字符串表示

更新时间:2023-02-03 08:02:28

因为 sprintf()"%.f" 等表达式有问题"1e-8",可能需要一些文字处理:

函数 convertFloat($floatAsString){$norm = strval(floatval($floatAsString));if (($e = strrchr($norm, 'E')) === false) {返回$标准;}返回 number_format($norm, -intval(substr($e, 1)));}

测试:

3 31.5 1.5-15.482e-2 -0.154821e-8 0.000000011e+3 1000-4.66E-2 -0.04663e-3 0.003

SO,

The problem

My question is about trivial thing: how to convert numeric string to it's plain ("native") representation. That means: if numeric string is already in plain view, leave it as it is, but if it is in scientific notation, convert it. Sample:

"3"          -->  "3"
"1.5"        -->  "1.5"
"-15.482E-2" -->  "-0.15482"

Numeric string supposed to be valid, and if it's not - then it's not a case for conversion (we're free to return null or empty string, for example).

Use-case

That is needed for bcmath because it can't work with scientific floats. Thus, they need to be converted to plain strings (asked here). So important consequence from this use-case is that numeric string can be something like 1E-300 or 1E+500. Since we're working with bcmath - it's intention is to handle such things.

My approach

For now, I've implemented that with , like:

function parseFloat($string)
{
   $string = (string)$string;
   if(preg_match('/^[+-]?(d+|d+.d*)[Ee]([+-]?)(d+)$/', $string, $matches))
   {
      $precision = false!==($dot=strpos($matches[1], '.'))
                   ?strlen($matches[1])-$dot-1
                   :0;
      $precision = $matches[2]=='-'
                   ?$precision + (int)$matches[3]
                   :$precision - (int)$matches[3];
      return number_format($string, $precision<0?0:$precision, '', '');
   }
   if(preg_match('/^[+-]?(d+|d+.d+)$/', $string))
   {
      return $string;
   }
}

The question

I feel that there should be more simple and wise way to do that. How to achieve that in more simple way in PHP? May be some tricky sprintf() format?

Important note: I don't want to deal with precision. I want black box. Pass something numeric there - got string as output. That's all. Don't want to deal with anything else. In fact, all my regex are about calculating length & precision - so, sure, if pass them explicitly (as parameters, for example) - we cat get rid of regex. But - no, that's not what I want.

Because sprintf() with "%.f" has trouble with expressions such as "1e-8", some text processing may be required:

function convertFloat($floatAsString)
{
    $norm = strval(floatval($floatAsString));

    if (($e = strrchr($norm, 'E')) === false) {
        return $norm;
    }

    return number_format($norm, -intval(substr($e, 1)));
}

Tested with:

3          3
1.5        1.5
-15.482e-2 -0.15482
1e-8       0.00000001
1e+3       1000
-4.66E-2   -0.0466
3e-3       0.003