preface

It’s a well-known problem with JavaScript binary precision, and floating point calculation accuracy can be missing. The classic example is why 0.1+0.2! = = 0.3

The ECMAScript specification defines the type of Number in accordance with ieee 754-2008’s 64-bit floating-point Number rule, which defines a maximum of 52 significant digits after decimals, resulting in a loss of accuracy.

But there are already a number of libraries on the web dedicated to this problem.

If you have any problems at work, doubts in the interview, or obstacles in the front end, you can join our front End Youdao Family. I will try my best to answer your questions and solve your doubts, so that we can work together and grow together.

Click to add technical exchange group or follow the public account 🎨 front youdao

directory

  • Primary packaging
  • big.js
    • Install and use
    • Operators operate on functions
  • bignumber.js
  • decimal.js
  • Math.js
  • conclusion

Primary packaging

add

/** ** add function, used to get exact add result ** Note: javascript add result will have error, when two floating point numbers add will be more obvious. This function returns a more accurate addition result. ** Calls: accAdd(arg1,arg2) ** Returns the exact result of arg1 plus arg2 **/
function accAdd(arg1, arg2) {
    let r1, r2, m
    try {
        r1 = arg1.toString().split('. ') [1].length
    } catch (e) {
        r1 = 0
    }
    try {
        r2 = arg2.toString().split('. ') [1].length
    } catch (e) {
        r2 = 0
    }
    m = Math.pow(10.Math.max(r1, r2))
    return (arg1 * m + arg2 * m) / m
}
Copy the code

Reduction of

/** ** subtraction function, used to get exact subtraction results ** Note: javascript subtraction results can be error, when two floating point numbers subtracting will be more obvious. This function returns a more accurate subtraction. ** Calls: accSub(arg1,arg2) ** Returns the exact result of arg1 plus arg2 **/
function accSub(arg1, arg2) {
  var r1, r2, m, n;
  try {
    r1 = arg1.toString().split(".") [1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".") [1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10.Math.max(r1, r2)); //last modify by deeka //
  n = r1 >= r2 ? r1 : r2;
  return ((arg1 * m - arg2 * m) / m).toFixed(n);
}
Copy the code

take

/** ** multiplication function, used to get exact multiplication results ** Note: javascript multiplication results have errors, which can be obvious when two floating point numbers are multiplied. This function returns a more accurate multiplication result. ** Call: accMul(arg1,arg2) ** Return value: arg1 times the exact result of arg2 **/
 
function accMul(arg1, arg2) {
    let m = 0
    let s1 = arg1.toString()
    let s2 = arg2.toString()
    try {
        m += s1.split('. ') [1]? s1.split('. ') [1].length : ' '
    } catch (e) {}
    try {
        m += s2.split('. ') [1]? s2.split('. ') [1].length : ' '
    } catch (e) {}
    return (Number(s1.replace('. '.' ')) * Number(s2.replace('. '.' '))) / Math.pow(10, m)
}
Copy the code

In addition to

/** ** division function, used to get the exact result of division ** note: javascript division results will be error, when two floating point number division will be more obvious. This function returns a more accurate division result. ** Calls accDiv(arg1,arg2) ** returns the exact result of arg1 divided by arg2 **/
function accDiv(arg1, arg2) {
    let t1 = 0
    let t2 = 0
    let r1
    let r2
    try {
        t1 = arg1.toString().split('. ') [1].length
    } catch (e) {}
    try {
        t2 = arg2.toString().split('. ') [1].length
    } catch (e) {}
    r1 = Number(arg1.toString().replace('. '.' '))
    r2 = Number(arg2.toString().replace('. '.' '))
    return (r1 / r2) * Math.pow(10, t2 - t1)
}
Copy the code

encapsulation

Method to define a function to invoke the addition, subtraction, multiplication, and division, do a good, use local method calls the addition, subtraction, multiplication, and division are consistent, assuming a method found behind the library better use or a platform is not compatible, the algorithm is not rigorous, extend new functions, etc., we just maintain this function, without considering the project in a component reference alone, New problems arising from this maintenance were not followed in this specification.

export const calcFn = {
    add() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) = > {
            return accAdd(total, num)
        })
    },
    sub() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) = > {
            return accSub(total, num)
        })
    },
    mul() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) = > {
            return accMul(total, num)
        })
    },
    divide() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) = > {
            return accDiv(total, num)
        })
    }
}
Copy the code

big.js

  • Introduction: small, fast, and easy to use library for arbitrary precision decimal arithmetic.
  • Features: currently the smallest package of the same type, no dependency, package size3 KBCompatible,ECMAScript 3+It works on all browsers.
  • Liverpoolfc.tv: making

Github.com/MikeMcl/big…

Install and use

The browser

<script src='https://cdn.jsdelivr.net/npm/[email protected]/big.min.js'></script>
Copy the code

Node.js

npm install big.js
Copy the code

use

x = new Big(0.1)
y = new Big(0.2)                 
z = new Big(0.3)
x.plus(y).eq(z)     // true
Copy the code

Operators operate on functions

The following big.js currently supports operators to manipulate functions.

  • abs, take the absolute value.
  • cmpCompare, short for compare.
  • divTo divide.
  • eq.equalEqual comparison.
  • gt, or more than.
  • gteIs less than or equal to, e representsequal.
  • ltThat is less than.
  • lteIs less than or equal to, e representsequal.
  • minusAnd subtraction.
  • modAnd take over.
  • plusAnd additive.
  • powAnd the power.
  • prec, rounded by precision, the parameter represents the overall number of digits.
  • round, rounded by precision, the parameter represents the number of decimal places.
  • sqrt, prescribing.
  • timesThe multiplication.
  • toExponential, into the scientific counting method, the parameter represents the precision number.
  • toFied, the parameter represents the number of decimal places.
  • toJSONandtoString, to a string.
  • toPrecisionIs displayed by the specified number of significant digits.
  • toNumber, intoJavaScriptIn thenumberType.
  • valueOf, containing a negative sign (if negative or -0).

encapsulation

import Big from 'big.js'

export const calcFn = {
    add() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) => {
            return new Big(total).plus(new Big(num))
        }).toString() * 1
    },
    sub() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) => {
            return new Big(total).minus(new Big(num))
        }).toString() * 1
    },
    mul() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) => {
            return new Big(total).times(new Big(num))
        }).toString() * 1
    },
    divide() {
        const arg = Array.from(arguments)
        return arg.reduce((total, num) => {
            return new Big(total).div(new Big(num))
        }).toString() * 1
    }
}
Copy the code

use

CalcFn. Add (0.1, 0.2). = = 0.3 / / falseCopy the code

bignumber.js

  • Introduction: JavaScript library for arbitrary precision decimal and non-decimal arithmetic.
  • Features: No dependencies, package size8 KBCompatible,ECMAScript 3+It works on all browsers.
  • Liverpoolfc.tv: making

Github.com/MikeMcl/big…

The usage method is similar, ibid.

decimal.js

  • Description: Provides JavaScript with arbitrary precision values of decimal type.
  • Features: No dependencies, package size12.6 KBCompatible,ECMAScript 3+It works on all browsers.
  • Liverpoolfc.tv: making

Github.com/MikeMcl/dec…

The usage method is similar, ibid.

Math.js

  • Simple math library written in Javascript, may not be maintained.
  • Features: is an extensive JavaScript and Node.js math library. It has a flexible expression parser, supports symbolic computation, comes with a large number of built-in functions and constants, and provides an integrated solution to handle different data types such as numbers, large numbers, complex numbers, fractions, units, and matrices. Powerful and easy to use.
  • Liverpoolfc.tv: making

conclusion

Big.js is suitable for most decimal arithmetic applications because NaN or Infinity are not accepted as legal values. Values of other cardinals are not supported. This works well if you don’t have non-decimal arithmetic in your project, and the key is that the package is too small.

Bignumber.js may be more suitable for financial applications because users don’t have to worry about losing accuracy unless they use operations that involve division.

Decimal.js may be better suited for more scientific applications because it can more efficiently handle very small or large values. For example, it does not have the limitation of bignumber.js, which attempts to perform a full precision operation when adding the value of a small exponent to the value of a large exponent, which may render the operation infeasible.

As mentioned above, decimal.js also supports non-integer powers and adds trig functions and exp, ln, and log methods. These additions make decimal.js significantly larger than bignumber.js.