How Lodash _.subtract Handles Floating-Point Numbers
This article examines how the _.subtract method in the
Lodash JavaScript library handles floating-point numbers. It explains
Lodash's internal mechanism for subtraction, details why native IEEE 754
binary floating-point precision issues persist within the library, and
provides clear solutions to prevent rounding errors in financial and
precision-critical applications.
Native Subtraction Behavior in Lodash
Lodash’s _.subtract(minuend, subtrahend) is a
lightweight mathematical utility. Under the hood, Lodash does not
implement custom arbitrary-precision arithmetic. Instead, it relies on
an internal helper created by createMathOperation, which
coerces values to numbers and applies standard JavaScript
subtraction:
const subtract = createMathOperation((minuend, subtrahend) => minuend - subtrahend, 0);Because it uses JavaScript's native binary subtraction operator
(-), _.subtract exhibits the exact same
floating-point characteristics and precision quirks found in vanilla
JavaScript.
The IEEE 754 Precision Issue
JavaScript stores numbers using 64-bit binary floating-point representation, following the IEEE 754 standard. Certain decimal fractions cannot be represented precisely in base-2 binary format, leading to minute rounding discrepancies.
When you subtract floating-point numbers with
_.subtract, these discrepancies become visible:
const _ = require('lodash');
// Expected: 0.2
console.log(_.subtract(0.3, 0.1));
// Output: 0.19999999999999998
// Expected: 1.1
console.log(_.subtract(1.4, 0.3));
// Output: 1.0999999999999999Lodash does not perform post-calculation rounding or truncation. If
precision drift occurs in native JavaScript, _.subtract
outputs that exact result.
Handling Floating-Point Errors
Because _.subtract is not intended to replace an
arbitrary-precision math library, developers must handle rounding
manually or use specialized tools.
1. Fixed Rounding with Native Methods
For standard user-facing displays where two decimal places suffice,
wrap the result with toFixed() or
Math.round:
const result = _.subtract(0.3, 0.1);
const formatted = Number(result.toFixed(2)); // 0.22. Using an Epsilon Comparison
When comparing results rather than displaying them, compare the
difference against Number.EPSILON:
const diff = _.subtract(0.3, 0.1);
const isEqual = Math.abs(diff - 0.2) < Number.EPSILON; // true3. Dedicated Decimal Libraries
For currency, billing, or scientific computing, do not rely on
_.subtract. Use libraries designed for arbitrary-precision
decimal arithmetic, such as decimal.js,
big.js, or bignumber.js:
const Decimal = require('decimal.js');
const result = new Decimal(0.3).minus(0.1).toNumber(); // 0.2