LibJS: Add non-BigInt overload of round_number_to_increment()

Unlike the spec we chose BigInt for the input and output types here as
it was being used with ℝ(ns), ns being of type BigInt, in one place and
a conversion to double would not be safe.
Since in many places we'll have double input values, let's add a double
overload of this function to avoid awkward conversions and expensive
allocations.
This commit is contained in:
Linus Groh 2021-10-06 22:25:28 +01:00
parent da804d95f7
commit 8b07453bce
Notes: sideshowbarker 2024-07-18 02:57:24 +09:00
2 changed files with 43 additions and 0 deletions

View file

@ -632,6 +632,48 @@ double constrain_to_range(double x, double minimum, double maximum)
return min(max(x, minimum), maximum);
}
// NOTE: We have two variants of this function, one using doubles and one using BigInts - most of the time
// doubles will be fine, but take care to choose the right one. The spec is not very clear about this, as
// it uses mathematical values which can be arbitrarily (but not infinitely) large.
// Incidentally V8's Temporal implementation does the same :^)
// 13.32 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
i64 round_number_to_increment(double x, u64 increment, StringView rounding_mode)
{
// 1. Assert: x and increment are mathematical values.
// 2. Assert: roundingMode is "ceil", "floor", "trunc", or "halfExpand".
VERIFY(rounding_mode == "ceil"sv || rounding_mode == "floor"sv || rounding_mode == "trunc"sv || rounding_mode == "halfExpand"sv);
// 3. Let quotient be x / increment.
auto quotient = x / (double)increment;
double rounded;
// 4. If roundingMode is "ceil", then
if (rounding_mode == "ceil"sv) {
// a. Let rounded be floor(quotient).
rounded = -floor(-quotient);
}
// 5. Else if roundingMode is "floor", then
else if (rounding_mode == "floor"sv) {
// a. Let rounded be floor(quotient).
rounded = floor(quotient);
}
// 6. Else if roundingMode is "trunc", then
else if (rounding_mode == "trunc"sv) {
// a. Let rounded be the integral part of quotient, removing any fractional digits.
rounded = trunc(quotient);
}
// 7. Else,
else {
// a. Let rounded be ! RoundHalfAwayFromZero(quotient).
rounded = round(quotient);
}
// 8. Return rounded × increment.
return (i64)rounded * (i64)increment;
}
// 13.32 RoundNumberToIncrement ( x, increment, roundingMode ), https://tc39.es/proposal-temporal/#sec-temporal-roundnumbertoincrement
BigInt* round_number_to_increment(GlobalObject& global_object, BigInt const& x, u64 increment, StringView rounding_mode)
{

View file

@ -102,6 +102,7 @@ Optional<u16> maximum_temporal_duration_rounding_increment(StringView unit);
ThrowCompletionOr<void> reject_temporal_calendar_type(GlobalObject&, Object&);
String format_seconds_string_part(u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Variant<StringView, u8> const& precision);
double constrain_to_range(double x, double minimum, double maximum);
i64 round_number_to_increment(double, u64 increment, StringView rounding_mode);
BigInt* round_number_to_increment(GlobalObject&, BigInt const&, u64 increment, StringView rounding_mode);
ThrowCompletionOr<ISODateTime> parse_iso_date_time(GlobalObject&, String const& iso_string);
ThrowCompletionOr<TemporalInstant> parse_temporal_instant_string(GlobalObject&, String const& iso_string);