1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 10:37:34 +00:00

LibJS: Fix rounding issues in Number.toFixed

toFixed was not rounding properly when trimming a number.
ie: (0.00006).toFixed(4) should be "0.00001" but was returning "0.0000"
This commit is contained in:
Ben Abraham 2022-03-02 00:15:00 -05:00 committed by Andreas Kling
parent 1eb451b8ce
commit a9c9c8c076
2 changed files with 37 additions and 2 deletions

View file

@ -269,16 +269,50 @@ JS_DEFINE_NATIVE_FUNCTION(NumberPrototype::to_fixed)
// 8. Let s be the empty String.
// 9. If x < 0, then
// a. Set s to "-".
auto s = (number < 0 ? "-" : "");
// b. Set x to -x.
if (number < 0)
number = -number;
// 10. If x ≥ 10^21, then
if (fabs(number) >= 1e+21)
return js_string(vm, MUST(number_value.to_string(global_object)));
// 11. Else,
// a-c. NOTE: The number to string formatting algorithm is handled by String::formatted().
// a. Let n be an integer for which n / (10^f) - x is as close to zero as possible. If there are two such n, pick the larger n.
// FIXME: This breaks down with values of `fraction_digits` > 23
auto n = round(pow(10.0f, fraction_digits) * number);
// b. If n = 0, let m be the String "0". Otherwise, let m be the String value consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
auto m = (n == 0 ? "0" : String::formatted("{}", n));
// c. If f ≠ 0, then
if (fraction_digits != 0) {
// i. Let k be the length of m.
auto k = static_cast<size_t>(m.length());
// ii. If k ≤ f, then
if (k <= fraction_digits) {
// 1. Let z be the String value consisting of f + 1 - k occurrences of the code unit 0x0030 (DIGIT ZERO).
auto z = String::repeated('0', fraction_digits + 1 - k);
// 2. Set m to the string-concatenation of z and m.
m = String::formatted("{}{}", z, m);
// 3. Set k to f + 1.
k = fraction_digits + 1;
}
// iii. Let a be the first k - f code units of m.
// iv. Let b be the other f code units of m.
// v. Set m to the string-concatenation of a, ".", and b.
m = String::formatted("{}.{}",
m.substring_view(0, k - fraction_digits),
m.substring_view(k - fraction_digits, fraction_digits));
}
// 12. Return the string-concatenation of s and m.
return js_string(vm, String::formatted("{:0.{1}}", number, static_cast<size_t>(fraction_digits)));
return js_string(vm, String::formatted("{}{}", s, m));
}
// 19.2.1 Number.prototype.toLocaleString ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sup-number.prototype.tolocalestring

View file

@ -12,6 +12,7 @@ describe("correct behavior", () => {
[12.81646112, 3, "12.816"],
[84.23, 4, "84.2300"],
[3.00003, 5, "3.00003"],
[0.00006, 4, "0.0001"],
// Numbers >= 1e+21
[1e21, 5, "1e+21"],
[1e22, 0, "1e+22"],