Created
May 24, 2022 16:41
-
-
Save linusg/a4543e5f554a615fd1c1ee5dc50790e9 to your computer and use it in GitHub Desktop.
[WIP] Bigint AOs for https://github.com/tc39/proposal-temporal/commit/75279e5b1d721cc489d25a3aa431ed5308d7bf77
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 13.29 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-applyunsignedroundingmode | |
Crypto::SignedBigInteger apply_unsigned_rounding_mode(Crypto::SignedBigInteger const& x, Crypto::SignedBigInteger r1, Crypto::SignedBigInteger r2, Optional<UnsignedRoundingMode> const& unsigned_rounding_mode) | |
{ | |
// 1. If x is equal to r1, return r1. | |
if (x == r1) | |
return r1; | |
// 2. Assert: r1 < x < r2. | |
VERIFY(r1 < x && x < r2); | |
// 3. Assert: unsignedRoundingMode is not undefined. | |
VERIFY(unsigned_rounding_mode.has_value()); | |
// 4. If unsignedRoundingMode is zero, return r1. | |
if (unsigned_rounding_mode == UnsignedRoundingMode::Zero) | |
return r1; | |
// 5. If unsignedRoundingMode is infinity, return r2. | |
if (unsigned_rounding_mode == UnsignedRoundingMode::Infinity) | |
return r2; | |
// 6. Let d1 be x – r1. | |
auto d1 = x.minus(r1); | |
// 7. Let d2 be r2 – x. | |
auto d2 = r2.minus(x); | |
// 8. If d1 < d2, return r1. | |
if (d1 < d2) | |
return r1; | |
// 9. If d2 < d1, return r2. | |
if (d2 < d1) | |
return r2; | |
// 10. Assert: d1 is equal to d2. | |
VERIFY(d1 == d2); | |
// 11. If unsignedRoundingMode is half-zero, return r1. | |
if (unsigned_rounding_mode == UnsignedRoundingMode::HalfZero) | |
return r1; | |
// 12. If unsignedRoundingMode is half-infinity, return r2. | |
if (unsigned_rounding_mode == UnsignedRoundingMode::HalfInfinity) | |
return r2; | |
// 13. Assert: unsignedRoundingMode is half-even. | |
VERIFY(unsigned_rounding_mode == UnsignedRoundingMode::HalfEven); | |
// 14. Let cardinality be (r1 / (r2 – r1)) modulo 2. | |
auto cardinality = modulo((r1.divided_by(r2.minus(r1))).quotient, "2"_bigint); | |
// 15. If cardinality is 0, return r1. | |
if (cardinality == "0"_bigint) | |
return r1; | |
// 16. Return r2. | |
return r2; | |
} | |
// 13.30 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement | |
Crypto::SignedBigInteger round_number_to_increment(Crypto::SignedBigInteger const& x, u64 increment, StringView rounding_mode) | |
{ | |
VERIFY(rounding_mode == "ceil"sv || rounding_mode == "floor"sv || rounding_mode == "trunc"sv || rounding_mode == "halfExpand"sv); | |
// OPTIMIZATION: If the increment is 1 the number is always rounded | |
if (increment == 1) | |
return x; | |
auto increment_big_int = Crypto::UnsignedBigInteger::create_from(increment); | |
// 1. Let quotient be x / increment. | |
auto division_result = x.divided_by(increment_big_int); | |
// OPTIMIZATION: If there's no remainder the number is already rounded | |
if (division_result.remainder == Crypto::UnsignedBigInteger { 0 }) | |
return x; | |
bool is_negative; | |
// 2. If quotient < 0, then | |
if (division_result.quotient.is_negative()) { | |
// a. Let isNegative be true. | |
is_negative = true; | |
// b. Set quotient to -quotient. | |
division_result.quotient.negate(); | |
} | |
// 3. Else, | |
else { | |
// a. Let isNegative be false. | |
is_negative = false; | |
} | |
// 4. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode, isNegative). | |
auto unsigned_rounding_mode = get_unsigned_rounding_mode(rounding_mode, is_negative); | |
// 5. Let r1 be the largest integer such that r1 ≤ quotient. | |
auto r1 = division_result.quotient; | |
// 6. Let r2 be the smallest integer such that r2 > quotient. | |
auto r2 = division_result.quotient.plus("1"_bigint); | |
// 7. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2, unsignedRoundingMode). | |
auto rounded = apply_unsigned_rounding_mode(division_result.quotient, r1, r2, unsigned_rounding_mode); | |
// 8. If isNegative is true, set rounded to -rounded. | |
if (is_negative) | |
rounded.negate(); | |
// 9. Return rounded × increment. | |
return rounded.multiplied_by(increment_big_int); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment