From 45c725f2b283429ba7fecca117cbbb63d04299ed Mon Sep 17 00:00:00 2001 From: Mike Bostock <mbostock@gmail.com> Date: Sun, 16 Mar 2025 09:02:57 -0700 Subject: [PATCH] fix nice rounding error --- src/nice.js | 13 +++++++++---- test/nice-test.js | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/nice.js b/src/nice.js index 579b418c..1ef2de74 100644 --- a/src/nice.js +++ b/src/nice.js @@ -7,11 +7,16 @@ export default function nice(start, stop, count) { if (step === prestep || step === 0 || !isFinite(step)) { return [start, stop]; } else if (step > 0) { - start = Math.floor(start / step) * step; - stop = Math.ceil(stop / step) * step; + const i = Math.ceil(start / step); + const j = Math.floor(stop / step); + start = (i - (i * step > start)) * step; + stop = (j + (j * step < stop)) * step; } else if (step < 0) { - start = Math.ceil(start * step) / step; - stop = Math.floor(stop * step) / step; + const s = -step; + const i = Math.ceil(start * s); + const j = Math.floor(stop * s); + start = (i - (i / s > start)) / s; + stop = (j + (j / s < stop)) / s; } prestep = step; } diff --git a/test/nice-test.js b/test/nice-test.js index bbc4f708..bbfdf3f2 100644 --- a/test/nice-test.js +++ b/test/nice-test.js @@ -44,3 +44,19 @@ it("nice(start, stop, count) returns the expected values", () => { assert.deepStrictEqual(nice(132, 876, 5), [0, 1000]); assert.deepStrictEqual(nice(132, 876, 1), [0, 1000]); }); + +it("nice(start, stop, count) handles small steps precisely", () => { + assert.deepStrictEqual(nice(0.9299999999999999, 1.07, 5000), [0.92998, 1.07]); + assert.deepStrictEqual(nice(-1.07, -0.9299999999999999, 5000), [-1.07, -0.92998]); + assert.deepStrictEqual(nice(0.929999999999999, 1.07, 5000), [0.92998, 1.07]); + assert.deepStrictEqual(nice(-1.07, -0.929999999999999, 5000), [-1.07, -0.92998]); + assert.deepStrictEqual(nice(0.92999999999999, 1.07, 5000), [0.92998, 1.07]); + assert.deepStrictEqual(nice(-1.07, -0.92999999999999, 5000), [-1.07, -0.92998]); + assert.deepStrictEqual(nice(0.930000000000001, 1.07, 5000), [0.93, 1.07]); + assert.deepStrictEqual(nice(-1.07, -0.930000000000001, 5000), [-1.07, -0.93]); +}); + +it("nice(start, stop, count) handles large steps precisely", () => { + assert.deepStrictEqual(nice(0.929999999999999e10, 1.07e10, 5000), [0.92998e10, 1.07e10]); + assert.deepStrictEqual(nice(-1.07e10, -0.929999999999999e10, 5000), [-1.07e10, -0.92998e10]); +});