Skip to content

fix: round ties towards +Infinity in roundTo to match round()#94

Open
spokodev wants to merge 1 commit into
rawify:mainfrom
spokodev:fix/roundto-negative-ties
Open

fix: round ties towards +Infinity in roundTo to match round()#94
spokodev wants to merge 1 commit into
rawify:mainfrom
spokodev:fix/roundto-negative-ties

Conversation

@spokodev

Copy link
Copy Markdown

Problem

roundTo and round break exact-half ties differently. round rounds half towards +Infinity (mirroring Math.round, as the docs say), but roundTo rounds the magnitude (half away from zero). Since rounding to the nearest multiple of 1 is the same as integer rounding, x.round() and x.roundTo(1) must agree — yet they disagree on every negative half:

new Fraction(-1, 2).round()      //  0
new Fraction(-1, 2).roundTo(1)   // -1   ← differs

new Fraction(-3, 2).round()      // -1
new Fraction(-3, 2).roundTo(1)   // -2   ← differs

new Fraction(-1, 4).roundTo('1/2') // -1/2, but round-to-nearest gives 0

Non-tie values and all positive values were already correct; only negative exact halves were affected.

Cause

roundTo computes k = floor(n / d) on the unsigned magnitudes and bumps k on a tie with if (r + r >= d) k++, then re-applies the sign. Because the half is resolved on the magnitude, ties always round away from zero.

Fix

Use the same sign-aware tie-break that round already uses — round a half up only when the value is non-negative — so ties always break towards +Infinity regardless of the multiple:

if ((this['s'] >= C_ZERO ? C_ONE : C_ZERO) + r + r > d) {
  k++;
}

Tests

Added negative-tie cases to tests/fraction.test.js (-1/2, -3/2 to a multiple of 1; -1/4 to a multiple of 1/2) — red before, green after. Full suite green (317 passing). dist/ rebuilt to match (only the touched logic; no unrelated build churn).

`roundTo` rounded an exact half by magnitude (half away from zero), while
`round` rounds half towards +Infinity (mirroring Math.round, as documented).
Because rounding to the nearest multiple of 1 is the same as integer
rounding, `x.round()` and `x.roundTo(1)` must agree, but they disagreed on
every negative half:

    new Fraction(-1, 2).round()      //  0
    new Fraction(-1, 2).roundTo(1)   // -1   (now 0)
    new Fraction(-3, 2).round()      // -1
    new Fraction(-3, 2).roundTo(1)   // -2   (now -1)

Apply the same tie-breaking `round` uses: only round a half up when the
value is non-negative, so the half is broken towards +Infinity regardless
of the multiple.
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.

1 participant