I remember, I have written a sub awhile ago that converts a number of any size to scientific notation. This works on extremely large numbers as well and extremely small numbers. It successfully decodes scientific notation, of course, and it treats numbers as a string, so you don't lose any precision. This sub can EASILY be modified to return only the exponent part of a number, not the entire number. Then you should check if the exponent is a positive number, and then how big is it. If it's bigger than, let's say 15, then you know that the number would lose precision if it were treated as a number.
################################################## # v2022.06.30 # Converts a decimal number to scientific notation. # # This function converts a number to standard scientific notation. # This function expects to receive a decimal number, # and it returns a number in scientific notation. # Both the input and output numbers are treated as strings. # If the input string had any spaces, commas or any other illegal # characters, those are removed from the number. # # Example: # # Input: "" Output: "+0E+0" # Input: "-20.35" Output: "-2.035E+1" # Input: "0.000333E-12" Output: "+3.33E-16" # Input: "000.00001000" Output: "+1E-5" # Input: "$ 75,800.99 " Output: "+7.580099E+4" # Input: " (12.49) abc" Output: "-1.249E+1" # Input: " 2008300" Output: "+2.0083E+6" # Input: ".225E+76" Output: "+2.25E+75" # Input: "10,000,000,000,000,000,000,000,000,000,000,000,000,000" # Output: "+1E+40" # # Usage: STRING = SCI(STRING N) # sub SCI { defined $_[0] or return '+0E+0'; my $NUM = $_[0]; my $M = ''; # Mantissa will be stored here my $E = ''; # Exponent will be stored here my $SIGN = 43; # Is this a negative number? (43=pos 45=neg) my $DEC = -1; # Remember the position of the decimal point my $EX = 0; # Exponent (0=no_exp 1=exp_found 43=pos_exp 45=neg_e +xp) my $Z = -1; # Start position of the last zero my $N = -1; # Position of the first non-zero digit for (my $i = 0; $i < length($NUM); $i++) { my $c = vec($NUM, $i, 8); if ($EX) # PROCESS EXPONENT: { if (($c == 43 || $c == 45) && $EX == 1) { $EX = $c; } elsif ($c > 47 && $c < 58) { $E .= chr($c); } elsif (length($E)) { last; } # What comes after the exponent? Nothin +g! } else # PROCESS MANTISSA { if ($c > 47 && $c < 58) # Digits 0-9 { if ($c == 48) { if (length($M)) { $M .= '0'; } # Keep '0' digit only if +there are other digits in front of it if ($Z < 0) { $Z = length($M); } # Remember last insignifi +cant zero } else { $M .= chr($c); # Save digits other than +zero if ($N < 0) { $N = length($M); } $Z = -1; } } elsif ($c == 68 || $c == 69 || $c == 100 || $c == 101) # D/d/E +/e { if (length($M)) { $EX = 1; } # Exponent marker found! } elsif ($c == 46) { if ($DEC < 0) { if (length($M) == 0) { $M = '0'; } $DEC = length($M); # Decimal point found! } else { last; } # A second decimal point? +?? } elsif (($c == 45 || $c == 40) && length($M) == 0) { $SIGN = 45; # It's a negative number } } } if (length($M) == 0) { return '+0E+0'; } # Convert Exponent to a number for now if ($EX) { $EX = ($EX == 45) ? -$E : $E; } # Adjust exponent if (length($M) > 1) { if ($DEC == -1) { $EX = $EX + length($M) - 1; } # No decimal po +int if ($DEC >= 2) { $EX = $EX + $DEC - 1; } # Yes decimal p +oint } # Remove trailing zeros if ($Z > 0) { $M = substr($M, 0, $Z - 1); } # Add decimal point if possible. if ($N > 1) { if (length($M) > $N) { $M = substr($M, $N - 1, 1) . '.' . substr($M, $N); $EX = $EX - $N + 1; } } else { if (length($M) > 1) { $M = substr($M, 0, 1) . '.' . substr($M, 1); + } } return chr($SIGN) . $M . 'E' . ($EX < 0 ? '' : '+') . $EX; } print SCI('00002999999999999900000006.5544433377777777888888880000001' +); exit; # Outputs: # # +2.9999999999999000000065544433377777777888888880000001E+21 #
In reply to Re: Number too big to fit in integer
by harangzsolt33
in thread Number too big to fit in integer
by jpl
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |