Precision Loss
Classic cases where native JS arithmetic produces wrong results, compared against @wzo/calc's correct output.
Precision Loss
Basic Arithmetic
| Expression | Native JS | @wzo/calc |
|---|---|---|
0.1 + 0.2 | 0.30000000000000004 | '0.3' |
0.3 - 0.1 | 0.19999999999999998 | '0.2' |
1.4 - 0.1 | 1.2999999999999998 | '1.3' |
1.1 + 2.2 | 3.3000000000000003 | '3.3' |
0.1 * 0.2 | 0.020000000000000004 | '0.02' |
0.07 * 100 | 7.000000000000001 | '7' |
0.69 * 10 | 6.8999999999999995 | '6.9' |
0.3 / 0.1 | 2.9999999999999996 | '3' |
0.7 / 0.1 | 6.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'.