################################################## # 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_exp) 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? Nothing! } 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 insignificant 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 point if ($DEC >= 2) { $EX = $EX + $DEC - 1; } # Yes decimal point } # 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 #