diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp index 9ebdd27d5d..87f2dc2763 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp @@ -375,7 +375,7 @@ static ALWAYS_INLINE int log10floor(Value number) return as_string.length() - 1; } -static Value multiply(GlobalObject& global_object, Value lhs, i64 rhs) +static Value multiply(GlobalObject& global_object, Value lhs, i8 rhs) { if (lhs.is_number()) return Value(lhs.as_double() * rhs); @@ -384,7 +384,7 @@ static Value multiply(GlobalObject& global_object, Value lhs, i64 rhs) return js_bigint(global_object.vm(), lhs.as_bigint().big_integer().multiplied_by(rhs_bigint)); } -static Value divide(GlobalObject& global_object, Value lhs, i64 rhs) +static Value divide(GlobalObject& global_object, Value lhs, i8 rhs) { if (lhs.is_number()) return Value(lhs.as_double() / rhs); @@ -393,18 +393,48 @@ static Value divide(GlobalObject& global_object, Value lhs, i64 rhs) return js_bigint(global_object.vm(), lhs.as_bigint().big_integer().divided_by(rhs_bigint).quotient); } -static ALWAYS_INLINE Value multiply_by_power(GlobalObject& global_object, Value number, i64 exponent) +static Crypto::SignedBigInteger bigint_power(i8 base, i8 exponent) { - if (exponent < 0) - return divide(global_object, number, pow(10, -exponent)); - return multiply(global_object, number, pow(10, exponent)); + VERIFY(exponent >= 0); + + auto base_bigint = Crypto::SignedBigInteger::create_from(base); + auto result = Crypto::SignedBigInteger::create_from(1); + + for (i8 i = 0; i < exponent; ++i) + result = result.multiplied_by(base_bigint); + + return result; } -static ALWAYS_INLINE Value divide_by_power(GlobalObject& global_object, Value number, i64 exponent) +static ALWAYS_INLINE Value multiply_by_power(GlobalObject& global_object, Value number, i8 exponent) { - if (exponent < 0) - return multiply(global_object, number, pow(10, -exponent)); - return divide(global_object, number, pow(10, exponent)); + if (number.is_number()) + return Value(number.as_double() * pow(10, exponent)); + + if (exponent < 0) { + auto exponent_bigint = bigint_power(10, -exponent); + return js_bigint(global_object.vm(), number.as_bigint().big_integer().divided_by(exponent_bigint).quotient); + } + + auto exponent_bigint = bigint_power(10, exponent); + return js_bigint(global_object.vm(), number.as_bigint().big_integer().multiplied_by(exponent_bigint)); +} + +static ALWAYS_INLINE Value divide_by_power(GlobalObject& global_object, Value number, i8 exponent) +{ + if (number.is_number()) { + if (exponent < 0) + return Value(number.as_double() * pow(10, -exponent)); + return Value(number.as_double() / pow(10, exponent)); + } + + if (exponent < 0) { + auto exponent_bigint = bigint_power(10, -exponent); + return js_bigint(global_object.vm(), number.as_bigint().big_integer().multiplied_by(exponent_bigint)); + } + + auto exponent_bigint = bigint_power(10, exponent); + return js_bigint(global_object.vm(), number.as_bigint().big_integer().divided_by(exponent_bigint).quotient); } static ALWAYS_INLINE Value rounded(Value number) diff --git a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js index 897ac1a422..fa0fd040d5 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js @@ -78,6 +78,34 @@ describe("style=decimal", () => { expect(en.format(12.3456)).toBe("12.3456"); expect(en.format(12.34567)).toBe("12.3457"); expect(en.format(12.34561)).toBe("12.3456"); + expect(en.format(0.00000000000000000000000000000123)).toBe( + "0.000000000000000000000000000001230" + ); + expect(en.format(-0.00000000000000000000000000000123)).toBe( + "-0.000000000000000000000000000001230" + ); + expect(en.format(12344501000000000000000000000000000)).toBe( + "12,344,500,000,000,000,000,000,000,000,000,000" + ); + expect(en.format(-12344501000000000000000000000000000)).toBe( + "-12,344,500,000,000,000,000,000,000,000,000,000" + ); + expect(en.format(12344501000000000000000000000000000n)).toBe( + "12,344,500,000,000,000,000,000,000,000,000,000" + ); + expect(en.format(-12344501000000000000000000000000000n)).toBe( + "-12,344,500,000,000,000,000,000,000,000,000,000" + ); + + const enLargeMaxSignificantDigits = new Intl.NumberFormat("en", { + minimumSignificantDigits: 4, + maximumSignificantDigits: 21, + }); + expect(enLargeMaxSignificantDigits.format(1)).toBe("1.000"); + expect(enLargeMaxSignificantDigits.format(1n)).toBe("1.000"); + expect(enLargeMaxSignificantDigits.format(123456789123456789123456789123456789n)).toBe( + "123,456,789,123,456,789,123,000,000,000,000,000" + ); const ar = new Intl.NumberFormat("ar", { minimumSignificantDigits: 4,