Note: numbers which I'm talking about are currency, thus don't have more than two digits in fractional part.
I've tested 4 libraries (Decimal.js, Numeral.js, Big.js and Math.js) and a simple plain javascript implementation function (which uses Math.round
for cutting off fractional part) with two arithmetic operations:
- 0.55 * 100 => 55 // but it gives 55.00000000000001
- 0.2 + 0.1 => 0.3 // but it gives 0.30000000000000004
Test script (node v10.4.1, Ubuntu 16.04LTS)
const { Decimal } = require('decimal.js')
const numeral = require('numeral')
const Big = require('big.js')
const math = require('mathjs')
const assert = require('assert')
function roundMultiply () {
return Math.round(0.55 * 100)
}
function roundAdd () {
return Math.round((0.2 + 0.1) * 100) / 100
}
function decimalMultiply () {
return new Decimal(0.55).mul(new Decimal(100))
}
function decimalAdd () {
return new Decimal(0.2).add(new Decimal(0.1))
}
function numeralMultiply () {
return numeral(0.55).multiply(100).value()
}
function numeralAdd () {
return numeral(0.2).add(0.1).value()
}
function bigJsMultiply () {
return +(new Big(0.55).times(100))
}
function bigJsAdd () {
return +(new Big(0.2).add(0.1))
}
function mathJsMultiply () {
return math.number(math.multiply(math.fraction(0.55), 100))
}
function mathJsAdd () {
return math.number(math.add(math.fraction(0.2), math.fraction(0.1)))
}
function test (fun, funName) {
console.time(funName)
for (let i = 0; i < 100000; i++) {
fun()
}
console.timeEnd(funName)
}
console.log('test multiplication results...')
assert(String(roundMultiply()) === '55')
assert(String(decimalMultiply()) === '55')
assert(String(numeralMultiply()) === '55')
assert(String(bigJsMultiply()) === '55')
assert(String(mathJsMultiply()) === '55')
console.log('test multiplication performance...')
test(roundMultiply, 'roundMultiply')
test(decimalMultiply, 'decimalMultiply')
test(numeralMultiply, 'withNumeral')
test(bigJsMultiply, 'withBigJs')
test(mathJsMultiply, 'mathJsMultiply')
console.log('test adding results...')
assert(String(roundAdd()) === '0.3')
assert(String(decimalAdd()) === '0.3')
assert(String(numeralAdd()) === '0.3')
assert(String(bigJsAdd()) === '0.3')
assert(String(mathJsAdd()) === '0.3')
console.log('test adding performance...')
test(roundAdd, 'roundAdd')
test(decimalAdd, 'decimalAdd')
test(numeralAdd, 'numeralAdd')
test(bigJsAdd, 'bigJsAdd')
test(mathJsAdd, 'mathJsAdd')
Results
roundMultiply: 2.673ms
withBigJs: 123.759ms
decimalMultiply: 172.068ms
withNumeral: 206.626ms
mathJsMultiply: 255.870ms
roundAdd: 2.317ms
mathJsAdd: 68.212ms
numeralAdd: 139.752ms
decimalAdd: 184.210ms
bigJsAdd: 222.685ms
As you can see, roundAdd
and roundMultiply
are far ahead of all other functions.
My main question: are there operands having at most two digits in fractional part and such, which, when peforming simple arithmetic operations (+, -, *, /) with them, whould give incorrect result when using Math.round
? Because I can't see any reason why would I need to use any of those (or other libraries) taking into account their performance.