diff options
author | Timothy Flynn <trflynn89@pm.me> | 2022-07-18 10:01:02 -0400 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-07-18 23:37:31 +0100 |
commit | 4b415a23c14f8c61024033c2e748343c4eee6359 (patch) | |
tree | 2d86e0ec0c18bd6d0c8ec2024de0eb19745ed38c | |
parent | 8ee485c350c047b73f83df52594f4484f4319670 (diff) | |
download | serenity-4b415a23c14f8c61024033c2e748343c4eee6359.zip |
LibJS: Implement Intl.NumberFormat V3's [[RoundingIncrement]] changes
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp | 28 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/builtins/Intl/NumberFormat/NumberFormat.prototype.format.js | 112 |
2 files changed, 137 insertions, 3 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp index 6fea9b6e78..148ac58213 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp @@ -377,6 +377,20 @@ static ALWAYS_INLINE int log10floor(Value number) return as_string.length() - 1; } +static Value increment(GlobalObject& global_object, Value lhs) +{ + if (lhs.is_number()) + return Value(lhs.as_double() + 1); + return js_bigint(global_object.vm(), lhs.as_bigint().big_integer().plus("1"_bigint)); +} + +static Value decrement(GlobalObject& global_object, Value lhs) +{ + if (lhs.is_number()) + return Value(lhs.as_double() - 1); + return js_bigint(global_object.vm(), lhs.as_bigint().big_integer().minus("1"_bigint)); +} + static Value subtract(GlobalObject& global_object, Value lhs, Value rhs) { if (lhs.is_number()) @@ -1262,9 +1276,6 @@ RawFormatResult to_raw_precision(GlobalObject& global_object, Value number, int // ToRawFixedFn, https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/proposed.html#eqn-ToRawFixedFn static auto to_raw_fixed_function(GlobalObject& global_object, Value number, int fraction, int rounding_increment, PreferredResult mode) { - // FIXME: Handle NumberFormat V3's [[RoundingIncrement]] option. - (void)rounding_increment; - struct { Value number; Value rounded; @@ -1296,6 +1307,17 @@ static auto to_raw_fixed_function(GlobalObject& global_object, Value number, int result.number = js_bigint(global_object.vm(), result.number.as_bigint().big_integer().plus("1"_bigint)); } + while (!modulo_is_zero(result.number, rounding_increment)) { + switch (mode) { + case PreferredResult::LessThanNumber: + result.number = decrement(global_object, result.number); + break; + case PreferredResult::GreaterThanNumber: + result.number = increment(global_object, result.number); + break; + } + } + result.rounded = divide_by_power(global_object, result.number, fraction); return result; } 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 7700a33c24..3ebd36f465 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 @@ -784,6 +784,118 @@ describe("style=decimal", () => { expect(ar.format(-1.2)).toBe("\u061c-\u0661\u066b\u0662"); }); + test("roundingIncrement", () => { + const nf = (roundingIncrement, fractionDigits) => { + return new Intl.NumberFormat([], { + roundingIncrement: roundingIncrement, + minimumFractionDigits: fractionDigits, + maximumFractionDigits: fractionDigits, + }); + }; + + const nf1 = nf(1, 2); + expect(nf1.format(1.01)).toBe("1.01"); + expect(nf1.format(1.02)).toBe("1.02"); + expect(nf1.format(1.03)).toBe("1.03"); + expect(nf1.format(1.04)).toBe("1.04"); + expect(nf1.format(1.05)).toBe("1.05"); + + const nf2 = nf(2, 2); + expect(nf2.format(1.01)).toBe("1.02"); + expect(nf2.format(1.02)).toBe("1.02"); + expect(nf2.format(1.03)).toBe("1.04"); + expect(nf2.format(1.04)).toBe("1.04"); + expect(nf2.format(1.05)).toBe("1.06"); + + const nf5 = nf(5, 2); + expect(nf5.format(1.01)).toBe("1.00"); + expect(nf5.format(1.02)).toBe("1.00"); + expect(nf5.format(1.03)).toBe("1.05"); + expect(nf5.format(1.04)).toBe("1.05"); + expect(nf5.format(1.05)).toBe("1.05"); + + const nf10 = nf(10, 2); + expect(nf10.format(1.1)).toBe("1.10"); + expect(nf10.format(1.12)).toBe("1.10"); + expect(nf10.format(1.15)).toBe("1.20"); + expect(nf10.format(1.2)).toBe("1.20"); + + const nf20 = nf(20, 2); + expect(nf20.format(1.05)).toBe("1.00"); + expect(nf20.format(1.1)).toBe("1.20"); + expect(nf20.format(1.15)).toBe("1.20"); + expect(nf20.format(1.2)).toBe("1.20"); + + const nf25 = nf(25, 2); + expect(nf25.format(1.25)).toBe("1.25"); + expect(nf25.format(1.3125)).toBe("1.25"); + expect(nf25.format(1.375)).toBe("1.50"); + expect(nf25.format(1.5)).toBe("1.50"); + + const nf50 = nf(50, 2); + expect(nf50.format(1.5)).toBe("1.50"); + expect(nf50.format(1.625)).toBe("1.50"); + expect(nf50.format(1.75)).toBe("2.00"); + expect(nf50.format(1.875)).toBe("2.00"); + expect(nf50.format(2.0)).toBe("2.00"); + + const nf100 = nf(100, 3); + expect(nf100.format(1.1)).toBe("1.100"); + expect(nf100.format(1.125)).toBe("1.100"); + expect(nf100.format(1.15)).toBe("1.200"); + expect(nf100.format(1.175)).toBe("1.200"); + expect(nf100.format(1.2)).toBe("1.200"); + + const nf200 = nf(200, 3); + expect(nf200.format(1.2)).toBe("1.200"); + expect(nf200.format(1.25)).toBe("1.200"); + expect(nf200.format(1.3)).toBe("1.400"); + expect(nf200.format(1.35)).toBe("1.400"); + expect(nf200.format(1.4)).toBe("1.400"); + + const nf250 = nf(250, 3); + expect(nf250.format(1.25)).toBe("1.250"); + expect(nf250.format(1.3125)).toBe("1.250"); + expect(nf250.format(1.375)).toBe("1.500"); + expect(nf250.format(1.4375)).toBe("1.500"); + expect(nf250.format(1.5)).toBe("1.500"); + + const nf500 = nf(500, 3); + expect(nf500.format(1.5)).toBe("1.500"); + expect(nf500.format(1.625)).toBe("1.500"); + expect(nf500.format(1.75)).toBe("2.000"); + expect(nf500.format(1.875)).toBe("2.000"); + expect(nf500.format(2.0)).toBe("2.000"); + + const nf1000 = nf(1000, 4); + expect(nf1000.format(1.1)).toBe("1.1000"); + expect(nf1000.format(1.125)).toBe("1.1000"); + expect(nf1000.format(1.15)).toBe("1.2000"); + expect(nf1000.format(1.175)).toBe("1.2000"); + expect(nf1000.format(1.2)).toBe("1.2000"); + + const nf2000 = nf(2000, 4); + expect(nf2000.format(1.2)).toBe("1.2000"); + expect(nf2000.format(1.25)).toBe("1.2000"); + expect(nf2000.format(1.3)).toBe("1.4000"); + expect(nf2000.format(1.35)).toBe("1.4000"); + expect(nf2000.format(1.4)).toBe("1.4000"); + + const nf2500 = nf(2500, 4); + expect(nf2500.format(1.25)).toBe("1.2500"); + expect(nf2500.format(1.3125)).toBe("1.2500"); + expect(nf2500.format(1.375)).toBe("1.5000"); + expect(nf2500.format(1.4375)).toBe("1.5000"); + expect(nf2500.format(1.5)).toBe("1.5000"); + + const nf5000 = nf(5000, 4); + expect(nf5000.format(1.5)).toBe("1.5000"); + expect(nf5000.format(1.625)).toBe("1.5000"); + expect(nf5000.format(1.75)).toBe("2.0000"); + expect(nf5000.format(1.875)).toBe("2.0000"); + expect(nf5000.format(2.0)).toBe("2.0000"); + }); + test("trailingZeroDisplay=auto", () => { const en = new Intl.NumberFormat("en", { trailingZeroDisplay: "auto", |