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

Example of how to configure cross-domain failure repair in nginx

Nginx cross-domain configuration does not take ef...

Linux system command notes

This article describes the linux system commands....

Detailed tutorial on installing MYSQL under WINDOWS

1. Download the installation package -Choose the ...

Analysis of MySQL Aborted connection warning log

Preface: Sometimes, the session connected to MySQ...

How to draw a vertical line between two div tags in HTML

Recently, when I was drawing an interface, I enco...

Detailed explanation of keepAlive usage in Vue front-end development

Table of contents Preface keep-avlive hook functi...

A brief discussion on event-driven development in JS and Nodejs

Table of contents Event-driven and publish-subscr...

MySQL 5.7.18 version free installation configuration tutorial

MySQL is divided into installation version and fr...

Detailed explanation of EXT series file system formats in Linux

Linux File System Common hard disks are shown in ...

jQuery custom magnifying glass effect

This article example shares the specific code of ...

Implementation of element shuttle frame performance optimization

Table of contents background Solution New Questio...

A simple way to achieve scrolling effect with HTML tag marquee (must read)

The automatic scrolling effect of the page can be...