Takeshi Tokugawa YD
Takeshi Tokugawa YD

Reputation: 979

Convert number to BigInt or String when it's value exceeds Number.MAX_SAFE_INTEGER in ECMAScript

When we don't know the numerical value at advance, can we convert it to BigInt or String without value corruption?

const targetNumber: number = 90071992547409946; // suppose we don't know it in advance
function splitEach3DigitsGroupWithComma(targetNumber: number | bigint | string): string {
  if(targetNumber > Number.MAX_SAFE_INTEGER) {
    // targetNumber = BigInt(targetNumber); // 90071992547409952n
    // targetNumber = String(targetNumber); // 90071992547409950
    // We need to do something before proceed!
  }

  return String(targetNumber).replace(/\B(?=(?:\d{3})+(?!\d))/gu, ",");
}

Upvotes: 0

Views: 1599

Answers (2)

Redu
Redu

Reputation: 26191

If your number is bigger than Number._MAX_SAFE_INTEGER then you can not safely convert into BigInt as is.

Say your big integer is 134640597783270600 which is > Number._MAX_SAFE_INTEGER. If you do like

>  n = 134640597783270600;

>  BigInt(n);
<- 134640597783270592n // Wrong..!

So you should first check if n is bigger than Number._MAX_SAFE_INTEGER and if so just convert it to string first

>  BigInt(n > Number.MAX_SAFE_INTEGER ? n+"" : n);
<- 134640597783270600n // Correct..!

However, if n happens to be a big integer expressed in the exponential form like 7.576507751994453e+29 then this happens;

>  BigInt(7.576507751994453e+29+"");
   Uncaught SyntaxError: Cannot convert 7.576507751994453e+29 to a BigInt
    at BigInt (<anonymous>)
    at <anonymous>:1:1

At this time i think to be on the safe side, it's best to convert all those integers greater than Number.MAX_SAFE_INTEGER into String type first to test for exponential representation. So, despite we have a BigInt constructor in JS, apparently we still need a function.

function toBigInt(n){
  return n.toString().includes("e") ? BigInt(n)
                                    : BigInt(n+"");
}

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370989

If the targetNumber is neither already a BigInt nor a string at the point where you first can work with it, then it's a plain number - and in that case, it may only be as precise as a number can be, per the IEEE 754 standard. If you only have a number to work with to begin with, possible more precise values have already been lost earlier.

To maintain precision, ensure that the value stays as a BigInt or string from beginning to end. If it gets converted to a number at any time in between, and then that number gets used, it may have lost precision, depending on the number.

In other words, to do something like this, you need to start with something like

const targetNumber = '90071992547409946';

or

const targetNumber = 90071992547409946n;

It can't be done in the middle of the process, once you already only have a number, while maintaining precision.

Upvotes: 1

Related Questions