in reply to Number too big to fit in integer

You could check the length of a string first to see if it has too many digits. But some very large numbers might be stored in scientific notation, which then reduces the length of the string, so checking the string length won't give you an accurate estimate.

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 #


Merry Christmas!

Replies are listed 'Best First'.
Re^2: Number too big to fit in integer
by karlgoethebier (Abbot) on Dec 25, 2022 at 12:15 UTC
    "…Converts a decimal number to scientific notation…"

    What follows seems to me to be quite a lot of lines. See here for some alternatives: Decimal to Scientific notation. Speaking of qbasic: this is a kind of Retro computing, isn't it?

    «The Crux of the Biscuit is the Apostrophe»

      "See here for some alternatives"

      I see, but that alternative treats the input as a number, and as a result, you may lose precision sometimes.

      "Speaking of qbasic: this is a kind of Retro computing, isn't it?"

      Yes, I am a member of several old computer groups and BASIC groups on Facebook. I also like Windows XP and TinyPerl 5.8 which are both considered ancient stuff. But I like to push the limits to see how much modern stuff we can do with old hardware and software.

Re^2: Number too big to fit in integer
by jwkrahn (Abbot) on Dec 25, 2022 at 01:13 UTC
    defined $_[0] or return '+0E+0';

    Shouldn't that be:

    defined $_[0] or return 'NaN';
      It can be. That's up to you. At the time I wrote this sub, I wanted something that *ALWAYS* returns a number in scientific notation. Not just any number but a number in a specific format. You see, the return value ALWAYS starts with a plus or minus sign, then it's followed by ONE DIGIT, ( then a decimal point, then one or more digits ), then a letter 'E' which is then followed by a plus or minus sign, then a number. Stop.

      (I wrote this function in QBASIC first, and then I ported it to Perl. So, you can tell that the code has a QBASIC-ish style and structure. But it's okay. The main thing is that it works.)

Re^2: Number too big to fit in integer
by soonix (Chancellor) on Dec 26, 2022 at 14:58 UTC
    While the style is not very "perlish", I find the comments really commendable.