summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime
diff options
context:
space:
mode:
authorTimothy Flynn <trflynn89@pm.me>2022-01-02 12:45:52 -0500
committerLinus Groh <mail@linusgroh.de>2022-01-02 20:07:03 +0100
commitf16f3c46773d2ef38487e57ea840d8177064010e (patch)
tree786641b96b6916150b21da5be03f0e263ac8f76b /Userland/Libraries/LibJS/Runtime
parenta3149c11e54ef4a63dea6a2fdbdca4a012abbc38 (diff)
downloadserenity-f16f3c46773d2ef38487e57ea840d8177064010e.zip
LibJS: Update ToRawPrecision / ToRawFixed AO spec comments
This is a normative change in the Intl spec: https://github.com/tc39/ecma402/commit/f0f66cf There are two main changes here: 1. Converting BigInt/Number objects to mathematical values. 2. A change in how ToRawPrecision computes its exponent and significant digits. For (1), we do not yet support BigInt number formatting, thus already have coerced Number objects to a double. When BigInt is supported, the number passed into these methods will likely still be a Value, thus can be coereced then. For (2), our implementation already returns the expected edge-case results pointed out on the spec PR.
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
-rw-r--r--Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp51
1 files changed, 28 insertions, 23 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp
index c8524d1b4c..4561b0d933 100644
--- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp
@@ -1129,11 +1129,14 @@ RawFormatResult to_raw_precision(double number, int min_precision, int max_preci
{
RawFormatResult result {};
- // 1. Let p be maxPrecision.
+ // 1. Set x to ā„(x).
+ // FIXME: Support BigInt number formatting.
+
+ // 2. Let p be maxPrecision.
int precision = max_precision;
int exponent = 0;
- // 2. If x = 0, then
+ // 3. If x = 0, then
if (number == 0.0) {
// a. Let m be the String consisting of p occurrences of the character "0".
result.formatted_string = String::repeated('0', precision);
@@ -1144,31 +1147,28 @@ RawFormatResult to_raw_precision(double number, int min_precision, int max_preci
// c. Let xFinal be 0.
result.rounded_number = 0;
}
-
- // 3. Else,
+ // 4. Else,
else {
// FIXME: The result of these steps isn't entirely accurate for large values of 'p' (which
// defaults to 21, resulting in numbers on the order of 10^21). Either AK::format or
// our Number::toString AO (double_to_string in Value.cpp) will need to be improved
// to produce more accurate results.
- // a. Let e be the base 10 logarithm of x rounded down to the nearest integer.
+ // a. Let e and n be integers such that 10^(pā€“1) ā‰¤ n < 10^p and for which n Ɨ 10^(eā€“p+1) ā€“ x is as close to zero as possible.
+ // If there are two such sets of e and n, pick the e and n for which n Ɨ 10^(eā€“p+1) is larger.
exponent = log10floor(number);
double power = pow(10, exponent - precision + 1);
-
- // b. Let n be an integer such that 10^(pā€“1) ā‰¤ n < 10^p and for which the exact mathematical value of n Ɨ 10^(eā€“p+1) ā€“ x
- // is as close to zero as possible. If there is more than one such n, pick the one for which n Ɨ 10^(eā€“p+1) is larger.
double n = round(number / power);
- // c. Let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
+ // b. Let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
result.formatted_string = Value(n).to_string_without_side_effects();
- // d. Let xFinal be n Ɨ 10^(eā€“p+1).
+ // c. Let xFinal be n Ɨ 10^(eā€“p+1).
result.rounded_number = n * power;
}
- // 4. If e ā‰„ pā€“1, then
+ // 5. If e ā‰„ pā€“1, then
if (exponent >= (precision - 1)) {
// a. Let m be the string-concatenation of m and eā€“p+1 occurrences of the character "0".
result.formatted_string = String::formatted(
@@ -1179,7 +1179,7 @@ RawFormatResult to_raw_precision(double number, int min_precision, int max_preci
// b. Let int be e+1.
result.digits = exponent + 1;
}
- // 5. Else if e ā‰„ 0, then
+ // 6. Else if e ā‰„ 0, then
else if (exponent >= 0) {
// a. Let m be the string-concatenation of the first e+1 characters of m, the character ".", and the remaining pā€“(e+1) characters of m.
result.formatted_string = String::formatted(
@@ -1190,7 +1190,7 @@ RawFormatResult to_raw_precision(double number, int min_precision, int max_preci
// b. Let int be e+1.
result.digits = exponent + 1;
}
- // 6. Else,
+ // 7. Else,
else {
// a. Assert: e < 0.
// b. Let m be the string-concatenation of the String value "0.", ā€“(e+1) occurrences of the character "0", and m.
@@ -1203,15 +1203,16 @@ RawFormatResult to_raw_precision(double number, int min_precision, int max_preci
result.digits = 1;
}
- // 7. If m contains the character ".", and maxPrecision > minPrecision, then
+ // 8. If m contains the character ".", and maxPrecision > minPrecision, then
if (result.formatted_string.contains('.') && (max_precision > min_precision)) {
// a. Let cut be maxPrecision ā€“ minPrecision.
int cut = max_precision - min_precision;
+ // Steps 8b-8c are implemented by cut_trailing_zeroes.
result.formatted_string = cut_trailing_zeroes(result.formatted_string, cut);
}
- // 8. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int }.
+ // 9. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int }.
return result;
}
@@ -1221,21 +1222,24 @@ RawFormatResult to_raw_fixed(double number, int min_fraction, int max_fraction)
{
RawFormatResult result {};
- // 1. Let f be maxFraction.
+ // 1. Set x to ā„(x).
+ // FIXME: Support BigInt number formatting.
+
+ // 2. Let f be maxFraction.
int fraction = max_fraction;
double power = pow(10, fraction);
- // 2. Let n be an integer for which the exact mathematical value of n / 10^f ā€“ x is as close to zero as possible. If there are two such n, pick the larger n.
+ // 3. Let n be an integer for which the exact mathematical value of n / 10^f ā€“ x is as close to zero as possible. If there are two such n, pick the larger n.
double n = round(number * power);
- // 3. Let xFinal be n / 10^f.
+ // 4. Let xFinal be n / 10^f.
result.rounded_number = n / power;
- // 4. If n = 0, let m be the String "0". Otherwise, let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
+ // 5. If n = 0, let m be the String "0". Otherwise, let m be the String consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
result.formatted_string = n == 0.0 ? String("0"sv) : Value(n).to_string_without_side_effects();
- // 5. If f ā‰  0, then
+ // 6. If f ā‰  0, then
if (fraction != 0) {
// a. Let k be the number of characters in m.
auto decimals = result.formatted_string.length();
@@ -1262,17 +1266,18 @@ RawFormatResult to_raw_fixed(double number, int min_fraction, int max_fraction)
// e. Let int be the number of characters in a.
result.digits = a.length();
}
- // 6. Else, let int be the number of characters in m.
+ // 7. Else, let int be the number of characters in m.
else {
result.digits = result.formatted_string.length();
}
- // 7. Let cut be maxFraction ā€“ minFraction.
+ // 8. Let cut be maxFraction ā€“ minFraction.
int cut = max_fraction - min_fraction;
+ // Steps 9-10 are implemented by cut_trailing_zeroes.
result.formatted_string = cut_trailing_zeroes(result.formatted_string, cut);
- // 10. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int }.
+ // 11. Return the Record { [[FormattedString]]: m, [[RoundedNumber]]: xFinal, [[IntegerDigitsCount]]: int }.
return result;
}