2

我想四舍五入一个浮点数。例如,sprintf '%.4f', 0.12345退货0.1235sprintf '%.4f', 0.12325退货0.1232。对于第二个示例,我希望它打印出来0.1233,而不是0.1232.

sprintf在 Perl 中还不够好。Math::BigFloat可以,但是有点过头了。

有谁知道是否有其他有效的方法来四舍五入,或者 Perl 中是否有其他模块?

4

3 回答 3

1

舍入数字的确切方法sprintf取决于系统库如何舍入数字。如果您需要精确控制数字的舍入方式,您将需要使用一个明确实现所需舍入的库,或者编写一个函数来根据需要进行舍入。

例如,将一个正数四舍五入到任意精度,其中 5 舍入就可以了。

sub round {
    my $numer     = shift;
    my $precision = shift;
    return int($numer * 10 ** $precision + 0.5) * 10 ** -$precision;
}

但是,对于负数,这不能正确舍入,-0.12324 会错误地舍入为 -0.1231。5 应该四舍五入(即朝向正无穷大)的解决方案是使用floor而不是int.

use POSIX qw(floor);
sub round {
    my $numer     = shift;
    my $precision = shift;
    return floor($numer * 10 ** $precision + 0.5) * 10 ** -$precision;
}

如果相反 5 应该四舍五入到最大的绝对值(即远离 0 的舍入),那么您可以添加一个简单的负数检查以将它们朝正确的方向舍入。

sub round {
    my $numer     = shift;
    my $precision = shift;
    my $direction = $numer >= 0 ? 0.5 : -0.5;
    return int($numer * 10 ** $precision + $direction) * 10 ** -$precision;
}

在某些情况下使用更复杂的四舍五入规则,其中所有数字在一个方向上舍入 5 的偏差是不可接受的,并且浮点数的任何(十进制)舍入都可能由于其二进制格式的不精确而出现错误。

于 2012-07-18T14:32:25.270 回答
0

这对我有用:

print sprintf '%.*f', 4, 0.12325

你的代码也对我有用。您是否单独测试了该代码?
你能告诉我们你的 perl 版本吗(perl -v)?

于 2012-07-18T10:11:38.000 回答
0

Perl 的sprintf好坏取决于它输入的数据。没有与 0.12345 或 0.12325 完全相同的浮点数:

  • 最接近 0.12345 的浮点数正好是2223877495995551/2**54≈ 0.1234 5 0000000000004,这个值略大于输入。
  • 最接近 0.12325 的浮点数正好是4440549232587309/2**55≈ 0.1232 4 9999999999998,这个值略小于输入。

请注意,后者的第 5 位小数是 4 而不是 5。在通常的规则下四舍五入到小数点后 4 位时,它们必须分别为 0.1235 和 0.1232。

你说 usingMath::BigFloat有点矫枉过正,但似乎你真正想要的是十进制算术,所以矫枉过正是不可避免的。

于 2021-11-21T23:07:57.680 回答