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.0999999999999999

Lodash 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.2

2. 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; // true

3. 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