Precision Loss

Classic cases where native JS arithmetic produces wrong results, compared against @wzo/calc's correct output.

Precision Loss

Basic Arithmetic

ExpressionNative JS@wzo/calc
0.1 + 0.20.30000000000000004'0.3'
0.3 - 0.10.19999999999999998'0.2'
1.4 - 0.11.2999999999999998'1.3'
1.1 + 2.23.3000000000000003'3.3'
0.1 * 0.20.020000000000000004'0.02'
0.07 * 1007.000000000000001'7'
0.69 * 106.8999999999999995'6.9'
0.3 / 0.12.9999999999999996'3'
0.7 / 0.16.999999999999999'7'

toFixed Rounding Bugs

Number.prototype.toFixed silently drops the carry at certain .5 positions:

// "2.5"   ❌  should be "2.6"

import { calc } from '@wzo/calc';

(1.005).toFixed(2); // "1.00"  ❌  should be "1.01"
(2.55).toFixed(1)
calc('1.005', { _fmt: { decimals: 2, rounding: 'round' } }) // "1.01"  ✓
calc('2.55', { _fmt: { decimals: 1, rounding: 'round' } }) // "2.6"   ✓

Large Numbers (beyond MAX_SAFE_INTEGER)

// 100000000000000000000 ← loses 1

import { addStr } from '@wzo/calc'

Number('9007199254740993') // 9007199254740992 ← loses 1
99999999999999999 + 1 // 100000000000000000 ← loses 1
1e20 + 1
addStr('9007199254740993', '0') // "9007199254740993" ✓
addStr('99999999999999999', '1') // "100000000000000000" ✓
addStr('100000000000000000000', '1') // "100000000000000000001" ✓

Chained Addition

Does adding ten 0.1s equal 1? Not with native JS.

// 0.9999999999999999  ❌

import { addStr } from '@wzo/calc'

Array.from({ length: 10 }).fill(0.1).reduce((a, b) => a + b)

Array.from({ length: 10 }).fill(0.1).reduce((a, b) => addStr(String(a), String(b)), '0')
// "1"  ✓

Real-world: E-commerce Total

const 
price
= 9.99
const
qty
= 3
const
tax
= 0.07
const
discount
= 0.85
const
total
=
calc
(`${
price
} * ${
qty
} * (1 + ${
tax
}) * ${
discount
}`, {
_fmt
: {
decimals
: 2,
rounding
: 'round' },
}) // "27.26"
rounding: 'round' applies standard rounding; omitting it defaults to 'truncate'.