LibJS: Handle negativity in Temporal's ApplyUnsignedRoundingMode

I don't fully understand the BigInt math here, as the computation for
d1 and d2 don't align with the spec due to BigInt logic. This was
discussed a bit in SerenityOS's Discord some years ago:

https://discord.com/channels/830522505605283862/851522357734408232/978786665306918932

But some new tests in test262 indicate that we need to handle negative
values here, instead of just throwing away the sign.
This commit is contained in:
Timothy Flynn
2025-11-13 10:21:26 -05:00
committed by Tim Flynn
parent 48854a8e74
commit c7e4a99219
Notes: github-actions[bot] 2025-11-14 11:33:50 +00:00
2 changed files with 19 additions and 2 deletions

View File

@@ -947,10 +947,11 @@ Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedDivisionResu
return r2;
// 6. Let d1 be x r1.
auto d1 = x.remainder.unsigned_value();
auto const& d1 = x.remainder;
// 7. Let d2 be r2 x.
auto d2 = MUST(increment.minus(x.remainder.unsigned_value()));
auto d2 = x.remainder.is_negative() ? x.remainder.plus(increment) : x.remainder.minus(increment);
d2.negate();
// 8. If d1 < d2, return r1.
if (d1 < d2)

View File

@@ -52,6 +52,22 @@ describe("correct behavior", () => {
expect(instant.toString(options)).toBe(expected);
}
});
test("rounding", () => {
const instant = new Temporal.Instant(-999999999999999990n);
const roundedDown = "1938-04-24T22:13:20.000Z";
const roundedUp = "1938-04-24T22:13:20.001Z";
for (const roundingMode of ["halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven", "floor", "trunc"]) {
const options = { smallestUnit: "millisecond", roundingMode };
expect(instant.toString(options)).toBe(roundedDown);
}
for (const roundingMode of ["ceil", "expand"]) {
const options = { smallestUnit: "millisecond", roundingMode };
expect(instant.toString(options)).toBe(roundedUp);
}
});
});
describe("errors", () => {