Solution to JS out-of-precision number problem

Solution to JS out-of-precision number problem

The most understandable explanation of the accuracy problem

For example, the number 1÷3=0.33333333... Everyone knows that 3 will repeat infinitely, and mathematics can express it, but the computer needs to store it so that it can be retrieved and used next time. But 0.333333... this number repeats infinitely, how do you let the computer store it? No matter how big the computer's memory is, it can't store everything, right! So it can't store a value relative to mathematics, it can only store an approximate value, so when the computer stores it and then takes it out for use, there will be accuracy problems.

JS exceeds the precision of the number solution

1. The maximum safe number in js is Math.pow(2,53) - 1. If the number exceeds this, the precision will be lost. You can solve it by converting the number into a string, as follows:

// js maximum safe number: Math.pow(2, 53)-1

let a = '123456444565456.889'
let b = '121231456.32'
// a + b = '123456565796913.209'

function addTwo(a, b) {
    //1. Compare the lengths of two numbers and add 0 to the front of the shorter one
    if (a.length > b.length) {
        let arr = Array(a.length - b.length).fill(0);
        b = arr.join('') + b
    } else if (a.length < b.length) {
        let arr = Array(b.length - a.length).fill(0);
        a = arr.join('') + a
    }

    //2. Reverse the two numbers (this is because people are used to adding from left to right, but numbers are added from right to left, so reversing them is easier to understand)
    a = a.split('').reverse();
    b = b.split('').reverse();

    //3. Loop through two arrays and add them. If the sum is greater than 10, then sign = 1, and the value at the current position is (sum % 10)
    let sign = 0; //mark whether there is carry let newVal = []; //used to store the final result for (let j = 0; j < a.length; j++) {
        let val = a[j] / 1 + b[j] / 1 + sign; // Divide by 1 to ensure that they are all numbers. You can also use Number() here.
        if (val >= 10) {
            sign = 1;
            newVal.unshift(val % 10) // unshift is used here instead of push because it saves the need to use reverse
        } else {
            sign = 0;
            newVal.unshift(val)
        }
    }

    // The last addition needs to add a digit '1'
    return sign && newVal.unshift(sign) && newVal.join('') || newVal.join('')
}

// Refer to other friends' concise writing function addTwo(a,b) {
    let temp = 0
    let res = ''
    a = a.split('')
    b = b.split('')
    while(a.length || b.length || temp) {
        temp += Number(a.pop() || 0) + Number(b.pop() || 0)
        res = (temp%10) + res
        temp = temp > 9
    }
    return res.replace(/^0+/g, '')
}

2. When it comes to adding decimal parts, encapsulate the above method once and the complete implementation is as follows:

let a = '123456444565456.889'
let b = '121231456.32'
// a + b = '123456565796913.209'

function addTwo(a = '0',b = '0', isHasDecimal=false) {
    //1. Compare the lengths of two numbers and add 0 to the front of the shorter one
    if (a.length > b.length) {
        let arr = Array(a.length - b.length).fill(0);
        b = isHasDecimal && (b + arr.join('')) || arr.join('') + b
    } else if (a.length < b.length) {
        let arr = Array(b.length - a.length).fill(0);
        a = isHasDecimal && (a + arr.join('')) || arr.join('') + a
    }

    //2. Reverse the two numbers (this is because people are used to adding from left to right, but numbers are added from right to left, so reversing them is easier to understand)
    a = a.split('').reverse();
    b = b.split('').reverse();


    //3. Loop through two arrays and add them. If the sum is greater than 10, then sign = 1, and the value at the current position is (sum % 10)
    let sign = 0; //mark whether there is carry let newVal = []; //used to store the final result for (let j = 0; j < a.length; j++) {
        let val = a[j] / 1 + b[j] / 1 + sign; // Divide by 1 to ensure that they are all numbers. You can also use Number() here.
        if (val >= 10) {
            sign = 1;
            newVal.unshift(val % 10) // unshift is used here instead of push because it saves the need to use reverse
        } else {
            sign = 0;
            newVal.unshift(val)
        }
    }

    // The last addition needs to add a digit '1'
    return sign && newVal.unshift(sign) && newVal.join('') || newVal.join('')
}

function add(a,b) {
    let num1 = String(a).split('.')
    let num2 = String(b).split('.')
    let intSum = addTwo(num1[0], num2[0])
    let res = intSum

    if (num1.length>1 || num2.length > 1) {
        let decimalSum = addTwo(num1[1], num2[1], true)

        if (decimalSum.length > (num1[1]||'0').length && decimalSum.length > (num2[1]||'0').length) {
            intSum = addTwo(intSum, decimalSum[0])
            decimalSum = decimalSum.slice(1)
            res = `${intSum}.${decimalSum}`
        } else {
            res = `${intSum}.${decimalSum}`
        }
    }
    return res
}
console.log(add(a, b)) // 123456565796913.209
// console.log(add('325', '988')) // 1313

Look at some typical problems with JS digital precision loss

// Addition ======================
0.1 + 0.2 = 0.30000000000000004
0.7 + 0.1 = 0.7999999999999999
0.2 + 0.4 = 0.6000000000000001

// Subtraction ======================
1.5 - 1.2 = 0.30000000000000004
0.3 - 0.2 = 0.099999999999999998

// Multiplication ======================
19.9 * 100 = 1989.99999999999998
0.8 * 3 = 2.4000000000000004
35.41 * 100 = 3540.99999999999995

// Division ======================
0.3 / 0.1 = 2.99999999999999996
0.69 / 10 = 0.06899999999999999

Summarize

This is the end of this article about how to solve the problem of out-of-precision numbers in JS. For more relevant content about out-of-precision numbers in JS, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of how to avoid digital calculation precision errors in javascript
  • How to solve the problem of loss of numerical precision in JavaScript
  • Analysis and solution of the cause of JS digital precision loss

<<:  Installing MySQL 8.0.12 based on Windows

>>:  Teach you how to deploy Vue project with Docker

Recommend

Manual and scheduled backup steps for MySQL database

Table of contents Manual backup Timer backup Manu...

HTML+CSS+jQuery imitates the search hot list tab effect with screenshots

Copy code The code is as follows: <!DOCTYPE ht...

js to realize payment countdown and return to the home page

Payment countdown to return to the home page case...

Import backup between mysql database and oracle database

Import the data exported from the Oracle database...

MySQL GROUP_CONCAT limitation solution

effect: The GROUP_CONCAT function can concatenate...

Explaining immutable values ​​in React

Table of contents What are immutable values? Why ...

How to use stored procedures in MySQL to quickly generate 1 million records

Preface When testing, in order to test the projec...

How to get the height of MySQL innodb B+tree

Preface The reason why MySQL's innodb engine ...

Details on using order by in MySQL

Table of contents 1. Introduction 2. Main text 2....

How to set the border of a web page table

<br />Previously, we learned how to set cell...

A brief discussion on the correct posture of Tomcat memory configuration

1. Background Although I have read many blogs or ...

CentOS 7 cannot access the Internet after modifying the network card

Ping www.baidu.com unknown domain name Modify the...