planetp - 1 year ago 81
Perl Question

How to move the decimal point N places to the the left efficiently?

I have a bunch of decimal numbers (as strings) which I receive from an API. I need to 'unscale' them, i.e. divide them by some power of 10. This seems a simple task for integers, but I have decimals with no guaranteed range. So, basically I need a function that works like this:

``````move_point "12.34" 1; # "1.234"
move_point "12.34" 5; # "0.0001234"
``````

I'd rather not use floats to avoid any rounding errors.

This is a bit verbose, but should do the trick:

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

Demo:

``````my \$n = "12.34";

for my \$p (0..5) {
printf "%d  %s\n", \$p, move_point(\$n, \$p);
}

0  12.34
1  1.234
2  0.1234
3  0.01234
4  0.001234
5  0.0001234
``````
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download