I've had this code sitting around for a while. I've been contemplating pushing it out to CPAN one of these days:
use warnings;
use strict;
use Carp;
use POSIX;
use Scalar::Util qw(looks_like_number);
# this is just test junk...
print "0xab --> ", engnot(0xab), "\n";
pp(7777);
pp(0x55);
pp( 2 / 3 );
pp(-0.04567);
for my $n ( 0, 54321, 1, 10, 10_000, 0.9999, 666e27, 555e-30, 0xff ) {
+ print "$n --> ", engnot($n), "\n" }
sub pp { my $n = shift; print "$n --> ", engnot($n), "\n" }
# here's the actual code
sub engnot {
my $num = shift;
looks_like_number($num) or croak "$num not a number\n";
my $sign = ($num < 0) ? '-' : '';
$num = abs $num;
if ( ($num >= 1e27) or ($num <= 1e-27) ) {
return sprintf '%e', $num;
}
my %prefix = (
'-8' => 'y', '8' => 'Y',
'-7' => 'z', '7' => 'Z',
'-6' => 'a', '6' => 'E',
'-5' => 'f', '5' => 'P',
'-4' => 'p', '4' => 'T',
'-3' => 'n', '3' => 'G',
'-2' => 'u', '2' => 'M',
'-1' => 'm', '1' => 'k',
'0' => ''
);
my $e = floor( log($num) / log(1000) );
my $mult = 1000**$e;
$num = $num / $mult;
return $sign . $num . $prefix{$e};
}
__END__
output...
0xab --> 171
7777 --> 7.777k
85 --> 85
0.666666666666667 --> 666.666666666667m
-0.04567 --> -45.67m
0 --> 0.000000e+00
54321 --> 54.321k
1 --> 1
10 --> 10
10000 --> 10k
0.9999 --> 999.9m
6.66e+29 --> 6.660000e+29
5.55e-28 --> 5.550000e-28
255 --> 255
Update: See also String numerifier with SI prefix support and Number::Format |