5
\$\begingroup\$

I have the following short function code that converts Exponential (e-Notation) Numbers to Decimals, allowing the output of large number of decimal places.

I needed to cover all the e-notation syntax permitted by Javascript which include the following:

Valid e-notation numbers in Javascript:
   123e1    ==>  1230
   123E1    ==>  1230
   123e+1   ==>  1230
   123.e+1  ==>  1230   (with missing fractional part)
   123e-1   ==>  12.3
   0.1e-1   ==>  0.01
   .1e-1    ==>  0.01   (with missing whole part)
   -123e1   ==> -1230

The function does not attempt to trap NaN or undefined inputs but does attempt to cater for normal (non-e-notation) numbers; such numbers are returned "as is".

I have tried to provide enough comments on each line and tried to avoid (as far as possible!) the use of short-circuiting and conditional (ternary) operators for better clarity.

I have used the toLocaleString() method to automatically detect the decimal separator sign, but this, of course, assumes that the input string representing the number follows the machine's locale (especially when manually passed to the function).

For your review, comments, and improvements.

Thanks in advance.

/********************************************************
 * Converts Exponential (e-Notation) Numbers to Decimals
 ********************************************************
 * @function numberExponentToLarge()
 * @version  1.00
 * @param   {string}  Number in exponent format.
 *                   (other formats returned as is).
 * @return  {string}  Returns a decimal number string.
 * @author  Mohsen Alyafei
 * @date    12 Jan 2020
 *
 * Notes: No check is made for NaN or undefined inputs
 *
 *******************************************************/

function numberExponentToLarge(numIn) {
 numIn +="";                                            // To cater to numric entries
 var sign="";                                           // To remember the number sign
 numIn.charAt(0)=="-" && (numIn =numIn.substring(1),sign ="-"); // remove - sign & remember it
 var str = numIn.split(/[eE]/g);                        // Split numberic string at e or E
 if (str.length<2) return sign+numIn;                   // Not an Exponent Number? Exit with orginal Num back
 var power = str[1];                                    // Get Exponent (Power) (could be + or -)
 if (power ==0 || power ==-0) return sign+str[0];       // If 0 exponents (i.e. 0|-0|+0) then That's any easy one

 var deciSp = 1.1.toLocaleString().substring(1,2);  // Get Deciaml Separator
 str = str[0].split(deciSp);                        // Split the Base Number into LH and RH at the decimal point
 var baseRH = str[1] || "",                         // RH Base part. Make sure we have a RH fraction else ""
     baseLH = str[0];                               // LH base part.

  if (power>0) {   // ------- Positive Exponents (Process the RH Base Part)
     if (power> baseRH.length) baseRH +="0".repeat(power-baseRH.length); // Pad with "0" at RH
     baseRH = baseRH.slice(0,power) + deciSp + baseRH.slice(power);      // Insert decSep at the correct place into RH base
     if (baseRH.charAt(baseRH.length-1) ==deciSp) baseRH =baseRH.slice(0,-1); // If decSep at RH end? => remove it

  } else {         // ------- Negative Exponents (Process the LH Base Part)
     num= Math.abs(power) - baseLH.length;                               // Delta necessary 0's
     if (num>0) baseLH = "0".repeat(num) + baseLH;                       // Pad with "0" at LH
     baseLH = baseLH.slice(0, power) + deciSp + baseLH.slice(power);     // Insert "." at the correct place into LH base
     if (baseLH.charAt(0) == deciSp) baseLH="0" + baseLH;                // If decSep at LH most? => add "0"
  }
 return sign + baseLH + baseRH;                                          // Return the long number (with sign)
 }


// ------------- tests for e-notation numbers ---------------------
console.log(numberExponentToLarge("123E0"))       // 123
console.log(numberExponentToLarge("-123e+0"))     // -123
console.log(numberExponentToLarge("123e1"))       // 1230
console.log(numberExponentToLarge("123e3"))       // 123000
console.log(numberExponentToLarge("123e+3"))      // 123000
console.log(numberExponentToLarge("123E+7"))      // 1230000000
console.log(numberExponentToLarge("-123.456e+1")) // -1234.56
console.log(numberExponentToLarge("123.456e+4"))  // 1234560
console.log(numberExponentToLarge("123E-0"))      // 123
console.log(numberExponentToLarge("123.456e+50")) // 12345600000000000000000000000000000000000000000000000

console.log(numberExponentToLarge("123e-0"))      // 123
console.log(numberExponentToLarge("123e-1"))      // 12.3
console.log(numberExponentToLarge("123e-3"))      // 0.123
console.log(numberExponentToLarge("-123e-7"))     // -0.0000123
console.log(numberExponentToLarge("123.456E-1"))  // 12.3456
console.log(numberExponentToLarge("123.456e-4"))  // 12.3456
console.log(numberExponentToLarge("123.456e-50")) //0.00000000000000000000000000000000000000000000000123456

console.log(numberExponentToLarge("1.e-5"))       // 0.00001  (handle missing base fractional part)
console.log(numberExponentToLarge(".123e3"))      // 123      (handle missing base whole part)

// The Electron's Mass: 
console.log(numberExponentToLarge("9.10938356e-31")) // 0.000000000000000000000000000000910938356
// The Earth's Mass:
console.log(numberExponentToLarge("5.9724e+24"))     // 5972400000000000000000000
// Planck constant:
console.log(numberExponentToLarge("6.62607015e-34")) // 0.000000000000000000000000000000000662607015


// ------------- testing for Non e-Notation Numbers -------------
console.log(numberExponentToLarge("12345.7898"))         // 12345.7898 (no exponent)
console.log(numberExponentToLarge(12345.7898))           // 12345.7898 (no exponent)
console.log(numberExponentToLarge(0.00000000000001))     // 0.00000000000001    (from 1e-14)
console.log(numberExponentToLarge(-0.0000000000000345))  // -0.0000000000000345 (from -3.45e-14)
console.log(numberExponentToLarge(-0))                   // 0

\$\endgroup\$
3
  • \$\begingroup\$ Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. \$\endgroup\$
    – Mast
    Jun 1 '20 at 4:51
  • \$\begingroup\$ @Mast nothing was added to the code from code feedback. In fact (as you can see) updates/typos were done before any review or code comments. Posts below are suggested alternative codes and are completely different codes and none address the code posted. \$\endgroup\$ Jun 1 '20 at 5:02
  • \$\begingroup\$ Please save the updates for a follow-up question. \$\endgroup\$
    – Mast
    Jun 1 '20 at 5:38
2
\$\begingroup\$

You can simply use the Number function to convert a string in scientific notation to a number

Number("123e1") === 1230

For converting number to string for big numbers, you can use:

// https://stackoverflow.com/a/50978675
myNumb.toLocaleString('fullwide', { useGrouping: false })

Here's a snippet:

const strings = ["1e+21","123E1","123e+1","123.e+1","123e-1","0.1e-1",".1e-1","-123e1"];

console.log(
  strings.map(s => Number(s).toLocaleString('fullwide', { useGrouping: false }))
)

\$\endgroup\$
5
  • \$\begingroup\$ The Number function does not handle this. e.g. Number("1e+21") gives the output back again in e-notation as 1e+21 not as a decimal number. The function can handle very large decimal digits and fractions. \$\endgroup\$ May 31 '20 at 8:29
  • 1
    \$\begingroup\$ That's how javascript displays numbers. Since, you want to get a string, you can convert it to a string. Updated the answer \$\endgroup\$
    – adiga
    May 31 '20 at 8:29
  • \$\begingroup\$ For "1e+21" you can use the new BigInt, so BigInt(Number("1e+21")).toLocaleString() \$\endgroup\$
    – KooiInc
    May 31 '20 at 8:34
  • \$\begingroup\$ @KooiInc BigInt doesn't work for decimals. I think OP is fine with losing precision for numbers > MAX_SAFE_INTEGER \$\endgroup\$
    – adiga
    May 31 '20 at 8:38
  • 1
    \$\begingroup\$ @KooiInc BigInt(Number("1e+24")).toLocaleString()) gives 999,999,999,999,999,983,222,784. BigInt(Number("1e+33")).toLocaleString()) gives 999,999,999,999,999,945,575,230,987,042,816. BigInt(Number("1e+55")).toLocaleString()) gives 10,000,000,000,000,000,102,350,670,204,085,511,496,304,388,135,324,745,728. Accuracy is lost of large numbers because you cannot use BigInt with e-notations directly. \$\endgroup\$ May 31 '20 at 10:43
1
\$\begingroup\$

Instead of console.log, you should write a proper unit test that actually compares the actual output with your expected output and only logs the failures.

The code itself looks good to me at first sight. It needs to be formatted consistently though, especially the spacing around operators.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks. In fact, I did write a test function that tests all possibilities and updated the code, but "@Mast" deleted the added test function. \$\endgroup\$ Jun 1 '20 at 5:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.