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

2022-08-31 01:02:17

所以

问题

我的问题是关于微不足道的事情:如何将数字字符串转换为它的简单(“本机”)表示形式。这意味着:如果数字字符串已经在普通视图中,请保持原样,但如果它是科学记数法,请转换它。样本:

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

数字字符串应该是有效的,如果不是 - 那么它就不是转换的情况(例如,我们可以自由地返回空或空字符串)。

使用案例

这是必要的,因为它不能与科学浮标一起使用。因此,需要将它们转换为普通字符串(此处询问)。此用例的重要结果是,数字字符串可以是类似于 或 .由于我们正在与之合作 - 它的目的是处理这些事情。bcmath1E-3001E+500bcmath

我的方法

现在,我已经用实现了它,比如:

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;
   }
}

问题

我觉得应该有更简单和明智的方法来做到这一点。如何在PHP中以更简单的方式实现这一点?可能是一些棘手的sprintf()格式?

重要提示:我不想处理精度问题。我想要黑匣子。在那里传递一些数字 - 得到字符串作为输出。就这样。不想处理其他任何事情。事实上,我所有的正则表达式都是关于计算长度和精度的 - 所以,当然,如果显式传递它们(例如作为参数) - 我们摆脱正则表达式。但是-不,这不是我想要的。


答案 1

因为 with 有问题,所以可能需要一些文本处理:sprintf()"%.f""1e-8"

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

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

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

测试依据:

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

答案 2

(更新为使用andufo建议的非折旧函数;我选择了,但如果你愿意,你可以使用。顺便说一句,如果有人仍然读到这一点,那么接受的答案失败了 - 尝试使用我的第一个和最后一个测试用例。explodepreg_split

我从Benjcarson在2002年发布的PHP板上挖出了一个小宝石,他注意到了你对bcmath和科学记数法的确切问题。

它需要一些调整(他的函数没有设置正确的刻度,并且在常规小数上失败,并且正如所指出的,它没有考虑刻度中小数位数的长度)

function exp2int($exp) {
  list($mantissa, $exponent) = explode("e", strtolower($exp));
  if($exponent=='') return $exp;
  list($int, $dec) = explode(".", $mantissa);
  bcscale (abs($exponent-strlen($dec)));
  return bcmul($mantissa, bcpow("10", $exponent));
}

作为旁注,您的原始代码在任何小于1E-40的数字上都失败

(与所有使用sprintf的当前答案一样)

如果您发布了更多的测试用例,调试会更容易,但这适用于您到目前为止发布的所有内容。

测试用例:

echo exp2int("-1.82235135978667123456789E5"); \\-182235.135978667123456789
echo exp2int("1.1350865232E-60"); \\0.0000000000000000000000000000000000000000000000000000000000011350865232
echo exp2int("-15.482E-2"); \\-0.15482
echo exp2int("1.5"); \\1.5
echo exp2int("3"); \\3
echo exp2int("123.123e10"); \\1231230000000.000 - you mentioned trailing 0's aren't a problem
echo exp2int("123.123e-10"); \\0.0000000123123
echo exp2int("123456789E-9"); \\0.123456789
echo exp2int("12345.6789E-5"); \\0.123456789
echo exp2int("1E-300"); \\0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001

推荐