Skip to content

fix(compat): round/ceil/floor should return Infinity for infinite values with precision - #1764

Merged
raon0211 merged 1 commit into
toss:mainfrom
chatman-media:fix/round-ceil-floor-infinity-precision
Jun 11, 2026
Merged

raon0211 merged 1 commit into
toss:mainfrom
chatman-media:fix/round-ceil-floor-infinity-precision

Conversation

@chatman-media

Copy link
Copy Markdown
Contributor

Summary

es-toolkit/compat aims for 100% behavioral parity with lodash, but round, ceil, and floor diverge when called on Infinity / -Infinity together with a non-zero precision: they return NaN instead of the infinite value.

import { round, ceil, floor } from 'es-toolkit/compat';

round(Infinity, 2);   // => NaN  (lodash: Infinity)
ceil(-Infinity, 2);   // => NaN  (lodash: -Infinity)
floor(Infinity, -2);  // => NaN  (lodash: Infinity)

// precision 0 / omitted already worked correctly:
round(Infinity);      // => Infinity ✓

Root cause

All three functions delegate to the internal decimalAdjust helper. When precision is non-zero it shifts the value using exponential string notation:

const [magnitude, exponent = 0] = number.toString().split('e');
let adjustedValue = Math[type](Number(`${magnitude}e${Number(exponent) + precision}`));

For Infinity, number.toString() is "Infinity", so the constructed string becomes "Infinitye2", which is not a valid number — Number("Infinitye2") is NaN. The precision === 0 path was unaffected because it skips this branch and calls Math[type](number) directly.

lodash guards this exact case in createRound by additionally checking that the number is finite before doing the exponential shift (lodash.js#L5481):

if (precision && nativeIsFinite(number)) { ... }

Fix

Mirror lodash by only applying the exponential-shift logic when the value is finite; otherwise fall through to Math[type](number), which returns the infinity unchanged.

-  if (precision) {
+  if (precision && Number.isFinite(Number(number))) {

The -0 handling is preserved (number may be the string '-0' at this point; Number('-0') is -0, which is finite), and NaN input still yields NaN via the fall-through, matching lodash.

Verification

  • Added should return Infinity for infinite values regardless of precision tests to round, ceil, and floor spec files. They fail on main (NaN) and pass with this fix.
  • Verified the new behavior matches lodash 4.17.21 across positive, negative, zero, and out-of-range precisions for both Infinity and -Infinity.
  • Full es-toolkit/compat test suite passes (3091 tests); a fuzz comparison of the string/number compat functions against lodash now reports zero discrepancies.
  • prettier and eslint clean on the changed files.

decimalAdjust is used only by round/ceil/floor, so the change is fully scoped to these three functions.

@vercel

vercel Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
es-toolkit Ready Ready Preview, Comment Jun 10, 2026 6:47pm

Request Review

@raon0211 raon0211 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your help!

@raon0211
raon0211 merged commit b2673a2 into toss:main Jun 11, 2026
10 checks passed

This branch was successfully deployed

1 active deployment
Preview — 37337002 Deployed Jun 10, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants