Lodash _.round Tie-Breaking Logic Explained
This article examines the exact tie-breaking mechanism executed by
the Lodash _.round utility when handling midpoint values.
It details how the function delegates rounding to JavaScript's standard
runtime, the behavior of its "round half toward positive infinity" rule
across positive and negative values, and how exponential string
manipulation is used to preserve precision during mid-point
evaluation.
Lodash Implementation Mechanism
Lodash does not implement a custom rounding algorithm or banker's
rounding (round half to even). Instead, _.round is
generated by an internal factory function called
createRound, which delegates directly to JavaScript’s
native Math.round.
When a precision parameter is supplied, Lodash converts the input
number into exponential notation via string manipulation to avoid binary
floating-point rounding errors. It shifts the decimal point by the
specified precision, calls Math.round on the shifted value,
and shifts the decimal back using exponential notation. Consequently,
the tie-breaking logic executed on the resulting midpoint is strictly
defined by ECMAScript's specification for Math.round.
The Tie-Breaking Rule: Round Half Toward Positive Infinity
When _.round encounters an exact midpoint value (where
the fractional component is precisely .5), it resolves the
tie using round half toward positive infinity (often
referred to as round-half-up).
The rule behaves as follows:
- If the fractional part is exactly
0.5, the number is rounded to the next integer in the direction of positive infinity (\(+\infty\)). - For positive numbers, this rounds away from zero. For example,
_.round(2.5)evaluates to3. - For negative numbers, rounding toward positive infinity means
rounding toward zero. For example,
_.round(-2.5)evaluates to-2, not-3.
Precision-Adjusted Midpoints
When rounding to specific decimal places using the
precision argument, the same rule applies after the decimal
shift:
_.round(1.55, 1)shifts to'15.5', evaluatesMath.round(15.5)to16, and shifts back to return1.6._.round(-1.55, 1)shifts to'-15.5', evaluatesMath.round(-15.5)to-15, and shifts back to return-1.5.
Because Lodash relies on exponential notation
(${number}e${precision}) rather than basic multiplication
(number * 10 ** precision), it minimizes floating-point
inaccuracies that frequently cause numbers like 1.005 to be
represented internally as 1.0049999999999999. Once
converted to a clean decimal representation, any exact .5
boundary reliably breaks toward positive infinity.