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 size
3 KB
Compatible,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.cmp
Compare, short for compare.div
To divide.eq
.equal
Equal comparison.gt
, or more than.gte
Is less than or equal to, e representsequal
.lt
That is less than.lte
Is less than or equal to, e representsequal
.minus
And subtraction.mod
And take over.plus
And additive.pow
And 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.times
The multiplication.toExponential
, into the scientific counting method, the parameter represents the precision number.toFied
, the parameter represents the number of decimal places.toJSON
andtoString
, to a string.toPrecision
Is displayed by the specified number of significant digits.toNumber
, intoJavaScript
In thenumber
Type.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 size
8 KB
Compatible,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 size
12.6 KB
Compatible,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.