Micheal J. Roberts
Micheal J. Roberts

Reputation: 4160

Javascript: converting very large and very small numbers to a fixed human readbale string

I have the following function which I thought would convert very large e.g., 1e+24 and very small, e.g., 1e-18 numbers to a fixed string, e.g., 1000000000000000000000000:

    convertExponentialToDecimal (exponentialNumber) {
      // Sanity Check - i.e., is it exponential number?
      const str = exponentialNumber.toString()
      if (str.indexOf('e-') !== -1) {
        const exponent = parseInt(str.split('-')[1], 10)
        return exponentialNumber.toFixed(exponent)
      }
      if (str.indexOf('e+') !== -1) {
        const exponent = parseInt(str.split('+')[1], 10)
        return exponentialNumber.toFixed(exponent)
      }
      return exponentialNumber
    }

However, for very large numbers - the process seems not to be working ...

i.e., a conversion of 1e+24 yields 1e+24, but 1e-18 yields 0.000000000000000001 as expected.

Can anyone spot the obvious issues, or have any pointers or even their own working solution for such a scenario...

If this is any insight - it works for anything less than 1e+21 ...

Upvotes: 2

Views: 664

Answers (2)

Jan Turoň
Jan Turoň

Reputation: 32912

Number type is IEEE754 float with double precision behind the curtain and it doesn't have enough precision to represent 1e24 digits. If you want to avoid treating numbers as strings, consider BigInt data type.

There are BigInt literals with n suffix and they don't support exponential notation, but luckily they do support **. For big numbers, you can use

10n**24n; // 1000000000000000000000000n

BigInts, are Int, without decimal point. But they are also Big, so you can afford fixed point notation, like first thousand digits are integer part, second thousand digits decimal part (the maximum size depends on available memory).

Upvotes: 1

malarres
malarres

Reputation: 2946

For your 'very large' part:

  if (str.indexOf('e+') !== -1) {
    let [a,b] = str.split('+')
    a = a.slice(0,-1)
    if (a.indexOf('.') !== -1) {
        b = parseInt(b) - (a.length - a.indexOf('.') -1)
    }
    return a.replace('.','')+"".padEnd(b,0)
  }

For your 'very small' part (though this would need to be tested, it works on my example but i didn't go through corner cases) :

if (str.indexOf('e-') !== -1) {
  const [a,b] = str.split('-')
  return '0.'+a.slice(0,-1).padStart(b,0).replace('.','')
}

Upvotes: 1

Related Questions