更新
我有一堆十进制数字(作为字符串),我从API接收。我需要"缩放"它们,即将它们除以10的某个幂。对于整数来说,这似乎是一个简单的任务,但是我有小数,没有保证范围。所以,基本上我需要一个这样的函数:
move_point "12.34" 1; # "1.234"
move_point "12.34" 5; # "0.0001234"
为了避免舍入错误,我宁愿不使用浮点数
这有点冗长,但应该能达到目的:
sub move_point {
my ($n, $places) = @_;
die 'negative number of places' if $places < 0;
return $n if $places == 0;
my ($i, $f) = split /./, $n; # split to integer/fractional parts
$places += length($f);
$n = sprintf "%0*s", $places+1, $i.$f; # left pad with enough zeroes
substr($n, -$places, 0, '.'); # insert the decimal point
return $n;
}
演示:my $n = "12.34";
for my $p (0..5) {
printf "%d %sn", $p, move_point($n, $p);
}
0 12.34
1 1.234
2 0.1234
3 0.01234
4 0.001234
5 0.0001234
除非您的数据包含比您显示的数字多得多的值,否则浮点值对于您的目的来说已经足够精确了。Perl可以可靠地再现最多16位的值
use strict;
use warnings 'all';
use feature 'say';
say move_point("12.34", 1); # "1.234"
say move_point("12.34", 5); # "0.0001234"
say move_point("1234", 12);
say move_point("123400", -9);
sub move_point {
my ($v, $n) = @_;
my $dp = $v =~ /.([^.]*)z/ ? length $1 : 0;
$dp += $n;
$v /= 10**$n;
sprintf '%.*f', $dp < 0 ? 0 : $dp, $v;
}
输出1.234
0.0001234
0.000000001234
123400000000000
更新
如果标准浮点数的限制实际上对你来说是不够的,那么核心Math::BigFloat
将满足你的需要
这个程序显示一个16位精度的数字,乘以从10E-20到10E20的所有数
use strict;
use warnings 'all';
use feature 'say';
use Math::BigFloat;
for ( -20 .. 20 ) {
say move_point('1234567890.1234567890', $_);
}
sub move_point {
my ($v, $n) = @_;
$v = Math::BigFloat->new($v);
# Build 10**$n
my $mul = Math::BigFloat->new(10)->bpow($n);
# Count new decimal places
my $dp = $v =~ /.([^.]*)z/ ? length $1 : 0;
$dp += $n;
$v->bdiv($mul);
$v->bfround(-$dp) if $dp >= 0;
$v->bstr;
}
输出123456789012345678900000000000
12345678901234567890000000000
1234567890123456789000000000
123456789012345678900000000
12345678901234567890000000
1234567890123456789000000
123456789012345678900000
12345678901234567890000
1234567890123456789000
123456789012345678900
12345678901234567890
1234567890123456789
123456789012345678.9
12345678901234567.89
1234567890123456.789
123456789012345.6789
12345678901234.56789
1234567890123.456789
123456789012.3456789
12345678901.23456789
1234567890.123456789
123456789.0123456789
12345678.90123456789
1234567.890123456789
123456.7890123456789
12345.67890123456789
1234.567890123456789
123.4567890123456789
12.34567890123456789
1.234567890123456789
0.1234567890123456789
0.01234567890123456789
0.001234567890123456789
0.0001234567890123456789
0.00001234567890123456789
0.000001234567890123456789
0.0000001234567890123456789
0.00000001234567890123456789
0.000000001234567890123456789
0.0000000001234567890123456789
0.00000000001234567890123456789