在PHP中将数字格式化为N个有效数字

16

我想将浮点数(双精度数)格式化为2位有效数字,例如:

1        => 1
11       => 11
111      => 110
119      => 120
0.11     => 0.11
0.00011  => 0.00011
0.000111 => 0.00011

因此,任意精度保持不变。

我希望已经有一些很好的函数内置了,但是到目前为止还没有找到任何函数。

有人指向了如何在php中向下舍入到最近的有效数字,这很接近,但不适用于N个有效数字,并且我不确定它对0.000XXX数字做了什么。


那你的问题是什么?你需要我们为你找到或编写函数吗? - Pitchinnate
1
如果您知道已存在这样的代码,请告诉我。我宁愿不自己编写,因为我相信它以前已经被写过了。 - Pavel Niedoba
2
可能是如何在php中将数字四舍五入到最近的有效数字的重复问题。 - Don't Panic
3个回答

17

要将数字四舍五入到 n 个有效数字,您需要找出该数字的10的幂级数大小,并从 n 中减去该大小。

这对于简单的四舍五入很有效:

function sigFig($value, $digits)
{
    if ($value == 0) {
        $decimalPlaces = $digits - 1;
    } elseif ($value < 0) {
        $decimalPlaces = $digits - floor(log10($value * -1)) - 1;
    } else {
        $decimalPlaces = $digits - floor(log10($value)) - 1;
    }

    $answer = round($value, $decimalPlaces);
    return $answer;
}

这将得到以下结果:
0.0001234567 变为 0.0001235
123456.7 变为 123500

但是,像四位有效数字的10这样的值应该严格表示为10.00,以表示已知值的精度。

如果这是所需的输出,您可以使用以下内容:

function sigFig($value, $digits)
{
    if ($value == 0) {
        $decimalPlaces = $digits - 1;
    } elseif ($value < 0) {
        $decimalPlaces = $digits - floor(log10($value * -1)) - 1;
    } else {
        $decimalPlaces = $digits - floor(log10($value)) - 1;
    }

    $answer = ($decimalPlaces > 0) ?
        number_format($value, $decimalPlaces) : round($value, $decimalPlaces);
    return $answer;
}

现在显示的是1.000而不是1。


感谢您抽出时间,我们已经转向您的解决方案。 - Pavel Niedoba
唯一的问题是当数字超过默认的printf精度指数和NAN时会出现问题。例如,我不知道为什么,但如果我想要用1个数字打印6.02e23,我希望得到600000000000000000000000。不过这只是小细节。 :) - PeterT
代码似乎存在一个错误:sigFig(0.9995, 3) 的输出结果为 1.000然而,根据 https://www.omnicalculator.com/math/sig-fig 的计算结果,输出应该是 1.00。 - koosvdkolk
sigFig(9.9995, 3) 输出的是10.00而不是10.0。通过添加以下代码进行修复:if (floor(log10($value, $decimalPlaces)) !== floor(log10(round($value, $decimalPlaces)))) { $decimalPlaces--; } - koosvdkolk

1

在对可能重复的答案进行少量修改后,参考Todd Chaffee的回答:

public static function roundRate($rate, $digits)
{
    $mod = pow(10, intval(round(log10($rate))));
    $mod = $mod / pow(10, $digits);
    $answer = ((int)($rate / $mod)) * $mod;
    return $answer;
}

这个并不能得到期望的结果。它向下取整,而不是四舍五入,并且它不允许负数。此外,有效数字的数量是不一致的:roundRate(3.333, 2) 返回 3.3,而 roundRate(2.222, 2) 返回 2.22。 - Adam Milward

-1

为了让sigFig(0.9995, 3)输出1.00,请使用以下代码:

if(floor(log10($value)) !== floor(log10(round($value, $decimalPlaces)))) {$decimalPlaces--;}

应该在声明$answer之前插入上述代码。

如果输入的$value是负数,则设置一个标志并在函数开头删除符号,如下所示:

if($value < 0){$flag = 1;} $value = ltrim($value, "-");

然后在返回$answer之前检测标志是否设置,如果设置,则恢复负号,如下所示:

if(isset($flag)){$answer = "-".$answer;}

最后,对于存在不确定有效数字位数的结果值(例如1000、12000等),可以使用sprintf或printf将结果用科学计数法表示到指定数量的有效数字位数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接