mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 10:08:10 +00:00
LibJS: Update ToRawPrecision / ToRawFixed AO spec comments
This is a normative change in the Intl spec:
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.
This commit is contained in:
parent
a3149c11e5
commit
f16f3c4677
1 changed files with 28 additions and 23 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue