Skip to content

fix(double): correct round for signed zero, the half boundary, and large integers - #3939

Merged
Kaida-Amethyst merged 4 commits into
moonbitlang:mainfrom
Lfan-ke:fix/round-edge-cases
Aug 4, 2026
Merged

fix(double): correct round for signed zero, the half boundary, and large integers#3939
Kaida-Amethyst merged 4 commits into
moonbitlang:mainfrom
Lfan-ke:fix/round-edge-cases

Conversation

@Lfan-ke

@Lfan-ke Lfan-ke commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Double::round was (self + 0.5).floor() (in both the generic and wasm files), which breaks in three ways on native/wasm-gc:

  • round(-0.0) and values in (-0.5, 0) lose the sign and return +0.0.
  • round(nextDown(0.5)) rounds up to 1.0 because nextDown(0.5) + 0.5 rounds to 1.0 before the floor.
  • integers in [2^52, 2^53) get perturbed because x + 0.5 is no longer exact there.

Reworked both to match the JS target (Math.round): pass NaN / infinities / |x| >= 2^52 through unchanged, map (0, 0.5) to +0 and [-0.5, 0] to -0, and otherwise floor(x + 0.5). The existing test compared with ==, which hides the sign of zero, so I added bit-level checks for the three cases.

Closes #3912

…rge integers

Closes moonbitlang#3912

Signed-off-by: 林晨 (Leo Cheng) <leo-cheng@vip.qq.com>
Comment thread builtin/double_round.mbt
Comment thread builtin/double_round_test.mbt
Comment thread builtin/double_round_wasm.mbt Outdated
(self + 0.5).floor()
// `(self + 0.5).floor()` alone drops the sign of zero, crosses the half
// boundary for `nextDown(0.5)`, and perturbs integers in `[2^52, 2^53)`.
if self != self || self.abs() >= 4503599627370496.0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same problem.

@Kaida-Amethyst

Copy link
Copy Markdown
Contributor

others lgtm. Thank you for your working ^_^

Lfan-ke added 2 commits August 4, 2026 15:46
…the sign-losing branch); add the +0.0 bit test in the native and wasm paths

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
…d test (moon fmt)

Signed-off-by: 林晨 (Leo Cheng) <chengkelfan@qq.com>
@Lfan-ke

Lfan-ke commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Addressed — thanks for catching that. round(0.0) was falling into the self >= -0.5 branch and returning -0.0; I added the self == 0.0 guard to the early return (which keeps the sign for both zeros) in the native and wasm paths, and added a bit-level test for +0.0. The js path delegates to Math.round, which already preserves the sign, so it's unchanged. CI is green.

@Kaida-Amethyst

Copy link
Copy Markdown
Contributor

Good Job

@Kaida-Amethyst
Kaida-Amethyst enabled auto-merge (squash) August 4, 2026 08:18
@Kaida-Amethyst
Kaida-Amethyst merged commit 6b0bcfb into moonbitlang:main Aug 4, 2026
15 checks passed
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.

[BUG] Double::round is incorrect for signed zero, half-boundary, and large-integer inputs

2 participants