Let’s start with an example

var number1 = 10000000000000000000000000 + 11111111111111111111111111 / / in theory the number1 value should be 21111111111111111111111111 (javascript is expressed as scientific notation: 2.111111111111111 e+25) var number2 = 21111111111111111111111000 console. The log (number1 = = = number2) / /true
Copy the code

You don’t have to do a simple look to know that the calculation is wrong, the last few bits should be 1, but why do you get a wrong value?

Error with JavaScript Number

Because the Number type of JavaScript is expressed in accordance with IEEE 754 specification, this means that JavaScript can accurately represent the Number is limited. The largest integer that JavaScript can accurately represent to the one digit is 9007199254740992, which is 2 to the power of 53. Beyond this range, accuracy is lost, causing JavaScript to be unable to determine the size, and the following phenomena occur:

Math.pow(2, 53);    // 9007199254740992
Math.pow(2, 53) === Math.pow(2, 53) + 1;    // true
9007199254740992 === 9007199254740992 + 1;    // true
Copy the code

The graph below shows the exact upper and lower limits for JavaScript numbers:

The solution

When two data are added, if one or both of them exceed the precision range, the result of direct addition will be inaccurate. How to solve this problem?

A common solution on the Internet is to convert Number to String, and then String to Array, and pay attention to the completion of the shorter Array, their length is the same and then add one by one to get a new Array, and then add the new Array into numbers, the following is the implementation code:

function sumString(a, b) {
  a = '0' + a;
  b = '0'+ b; / / add'0'Var arrA = a.split() var arrA = a.split() var arrA = a.split()' '), // Convert string to array arrB = b.split(' '), res = [], // Add the result of the array temp =' 'Distance = a.length-b.length, len = distance > 0, len = distance > 0, len = distance > 0, len = distance > 0 a.length : b.length; // The length of the sum // Increments the distance 0 before the value of the smaller length to ensure that the length of the two numbers is equal before adding themif(distance > 0) {
    for(let i = 0; i < distance; i++) {
      arrB.unShift('0'); }}else{
    for(let i = 0; i < distance; i++) {
      arrA.unShift('0'); }} // Now we have two arrays of the same length, all we need to do is add their values of the number of digits, the value greater than or equal to 10 is addedfor(let i = len-1; i >= 0; i--) {
    temp = Number(arrA[i]) + Number(arrB[i]) + carry;
    if(temp >= 10) {
      carry = 1;
      res.unshift((temp + ' ')[1])
    }
    else{
      carry = 0;
      res.unshift(temp)
    }
  }
  res = res.join(' ').replace(/^0/, ' ');
  console.log(res);
}
Copy the code

About 0.1 + 0.2! == 0.3 problem

As mentioned above, in JavaScript, floating point standard IEEE 754 is used to represent numbers. When representing decimals, some numbers cannot be completely converted when converting to binary, such as 0.3. Converting to binary is a long circular number, which is beyond the scope of JavaScript. So it’s approximately 0.30000000000000004.

This is the biggest problem with binary floating-point numbers (not just JavaScript, but all languages that follow the IEEE 754 specification).

How do you tell if two values want to be equal

Here we introduce a tiny constant Number.EPSILON that was added to the Number object in ES6. It represents the difference between 1 and the smallest floating point number greater than 1, equal to 2 to the -52.

Number.epsilon is actually the minimum precision that JavaScript can represent. If the error is less than that, it is considered meaningless, that is, there is no error.

So you can use this to determine if two floating-point numbers want to wait:

function numIsEqual(lef, rig) {
    return Math.abs(lef - rig) < Number.EPSILON
}
Copy the code

For browser compatibility you can write:

function numIsEqual(lef, rig) {
    let EPSILON = Number.EPSILON ? Number.EPSILON : Math.pow(2,-52)
    return Math.abs(lef - rig) < EPSILON
}
Copy the code

Of course we usually use decimals to two decimal places, it’s not too much of a problem, but remember toFied() with decimal places reserved, don’t take calculated values directly to avoid errors.

The tail

I’ve heard a bit about how data is represented in JavaScript before in Geek Time, which explained in detail why the IEEE 754 standard for floating-point numbers can only represent a limited number of numbers, but I’m still struggling with such low-level stuff.

reference

  • Js to achieve the addition of large numbers
  • How to solve JavaScript 0.1+0.2 does not equal 0.3
  • 【ES6 learning Notes 】Number