How can I disable scientific notation when working with very large numbers in Perl?
-
07-07-2019 - |
Question
Consider the following:
print 3 ** 333; #Yields 7.6098802313206e+158
My question is simple: How can I disable scientific notation when working with very large numbers? Basically, I'd like to see all the digits dumped to stdout
verbatim.
Is this possible?
Solution
See Math::BigInt
use Math::BigInt;
$x = Math::BigInt->new("3");
print $x ** 333;
Output:
760988023132059809720425867265032780727896356372077865117010037035791631439306199613044145649378522557935351570949952010001833769302566531786879537190794573523
OTHER TIPS
If you want to do it for all integers in your program, you can just add:
use bigint;
If you only want to do it for some integers, you can create Math::BigInt objects.
There is also bignum and Math::BigNum if you are working with floats.
For very small values see the following code:
my $value = 1e-07; # = 0.0000001
# NOPE
print $value; # prints 1e-07, $value is a number
print sprintf("%f", $value); # prints 0, $value is a number
print sprintf("%.10f", $value); # prints 0.0000001000, $value is a number
$value = sprintf("%.10f", $value);
print $value # prints 1e-07, $value is a number
# /NOPE
use bignum;
$value = ($value+0)->bstr();
print $value; # prints 0.0000001, $value is a string
no bignum;
print $value; # prints 0.0000001, $value is a string
# HOORAY
With numbers that large you may have more digits than the precision used to store the numbers. (Seeing a simple runnable example would have resolved this question).
If you really need to see all 150+ digits, you should use the bigint (for integers), bigrat (for rational numbers) and the bignum (for floating point numbers) modules.
Had the same issue with this code:
#!/usr/bin/perl
use strict;
use warnings;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = 1; $x <= 64; $x++ ) {
my $y = (2 ** $x);
printf( "2 ^ %4d = %20d to %-20d or %20d\n",
$x, $y/-2, $y/2, $y );
}
The last two lines where printing:
2 ^ 63 = -4611686018427387904 to 4611686018427387904 or -9223372036854775808
2 ^ 64 = -9223372036854775808 to -9223372036854775808 or -1
Obviously not right, and not realizing the %d conversion was causing the issue, I tried the solution flagged here:
#!/usr/bin/perl
use strict;
use warnings;
use Math::BigInt;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = Math::BigInt->new('1'); $x <= 64; $x++ ) {
my $y = Math::BigInt->new(2 ** $x);
printf( "2 ^ %4d = %20d to %-20d or %20d\n",
$x, $y/-2, $y/2, $y );
}
That's when I realized the printf 'd' conversion was causing an issue. Reading up on Math::BigInt it seems to suggest that these numbers are stored as strings inside, so changing to an 's' conversion, fixed the issue:
#!/usr/bin/perl
use strict;
use warnings;
use Math::BigInt;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = Math::BigInt->new('1'); $x <= 64; $x++ ) {
my $y = Math::BigInt->new(2 ** $x);
printf( "2 ^ %4s = %20s to %-20s or %20s\n",
$x, $y/-2, $y/2, $y );
}
Now the last two lines printed correctly:
2 ^ 63 = -4611686018427387904 to 4611686018427387904 or 9223372036854775808
2 ^ 64 = -9223372036854775808 to 9223372036854775808 or 18446744073709551616
But in regards to Karel's answer, which was almost correct IMHO, this could also be done without the use of BigInt (bigint, BigNum, ...) by using the 'f' conversion but with the precision set to '0' to eliminate those decimals:
#!/usr/bin/perl
use strict;
use warnings;
print "Base Exp MAX Signed-Negitive MAX Signed-Positive MAX Unsigned\n";
for( my $x = 1; $x <= 64; $x++ ) {
my $y = (2 ** $x);
printf( "2 ^ %4d = %20.0f to %-20.0f or %20.0f\n",
$x, $y/-2, $y/2, $y );
}
This also works for the OP's question:
perl -e 'printf "%.0f\n", 3 ** 333'
760988023132059813486251563646478824265752535077884574263917414498578085812167738721447369281049109603746001743233145041176969930222526036520619613114171654144