summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnonymous <anon@mous.org>2022-02-16 02:14:57 -0800
committerLinus Groh <mail@linusgroh.de>2022-02-16 11:18:41 +0000
commit1e0facb7ee71a8611052b4f87bd36a435d35050a (patch)
tree5d79ed00f44e5d4927a35c373dcc0514ba29bc95
parent602190f66f7d74bba019b42870d1fc93e5a26a51 (diff)
downloadserenity-1e0facb7ee71a8611052b4f87bd36a435d35050a.zip
LibJS: Implement the Number::remainder AO using fmod
The ECMA verbiage for modulus is the mathematical definition implemented by fmod, so let's just use that rather than trying to reimplement all the edge cases.
-rw-r--r--Userland/Libraries/LibJS/Runtime/Value.cpp35
-rw-r--r--Userland/Libraries/LibJS/Tests/operators/modulo-basic.js1
-rw-r--r--Userland/Libraries/LibJS/Tests/test-common.js3
3 files changed, 9 insertions, 30 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp
index 01f14e2be3..60e59714d4 100644
--- a/Userland/Libraries/LibJS/Runtime/Value.cpp
+++ b/Userland/Libraries/LibJS/Runtime/Value.cpp
@@ -1178,36 +1178,11 @@ ThrowCompletionOr<Value> mod(GlobalObject& global_object, Value lhs, Value rhs)
auto rhs_numeric = TRY(rhs.to_numeric(global_object));
if (both_number(lhs_numeric, rhs_numeric)) {
// 6.1.6.1.6 Number::remainder ( n, d ), https://tc39.es/ecma262/#sec-numeric-types-number-remainder
-
- // 1. If n is NaN or d is NaN, return NaN.
- if (lhs_numeric.is_nan() || rhs_numeric.is_nan())
- return js_nan();
-
- // 2. If n is +∞𝔽 or n is -∞𝔽, return NaN.
- if (lhs_numeric.is_positive_infinity() || lhs_numeric.is_negative_infinity())
- return js_nan();
-
- // 3. If d is +∞𝔽 or d is -∞𝔽, return n.
- if (rhs_numeric.is_positive_infinity() || rhs_numeric.is_negative_infinity())
- return lhs_numeric;
-
- // 4. If d is +0𝔽 or d is -0𝔽, return NaN.
- if (rhs_numeric.is_positive_zero() || rhs_numeric.is_negative_zero())
- return js_nan();
-
- // 5. If n is +0𝔽 or n is -0𝔽, return n.
- if (lhs_numeric.is_positive_zero() || lhs_numeric.is_negative_zero())
- return lhs_numeric;
-
- // 6. Assert: n and d are finite and non-zero.
-
- auto index = lhs_numeric.as_double();
- auto period = rhs_numeric.as_double();
- auto trunc = (double)(i32)(index / period);
-
- // 7. Let r be ℝ(n) - (ℝ(d) × q) where q is an integer that is negative if and only if n and d have opposite sign, and whose magnitude is as large as possible without exceeding the magnitude of ℝ(n) / ℝ(d).
- // 8. Return 𝔽(r).
- return Value(index - trunc * period);
+ // The ECMA specification is describing the mathematical definition of modulus
+ // implemented by fmod.
+ auto n = lhs_numeric.as_double();
+ auto d = rhs_numeric.as_double();
+ return Value(fmod(n, d));
}
if (both_bigint(lhs_numeric, rhs_numeric)) {
if (rhs_numeric.as_bigint().big_integer() == BIGINT_ZERO)
diff --git a/Userland/Libraries/LibJS/Tests/operators/modulo-basic.js b/Userland/Libraries/LibJS/Tests/operators/modulo-basic.js
index c364feaddb..0c30123be9 100644
--- a/Userland/Libraries/LibJS/Tests/operators/modulo-basic.js
+++ b/Userland/Libraries/LibJS/Tests/operators/modulo-basic.js
@@ -23,6 +23,7 @@ test("basic functionality", () => {
expect(1 % -0).toBeNaN();
expect(0 % 5).toBe(0);
expect(-0 % 5).toBe(-0);
+ expect((-1) % -1).toBe(-0);
// test262 examples
expect(1 % null).toBeNaN();
diff --git a/Userland/Libraries/LibJS/Tests/test-common.js b/Userland/Libraries/LibJS/Tests/test-common.js
index 1f9e3af979..b02c9cb287 100644
--- a/Userland/Libraries/LibJS/Tests/test-common.js
+++ b/Userland/Libraries/LibJS/Tests/test-common.js
@@ -53,6 +53,9 @@ class ExpectationError extends Error {
const valueToString = value => {
try {
+ if (value === 0 && 1 / value < 0) {
+ return "-0";
+ }
return String(value);
} catch {
// e.g for objects without a prototype, the above throws.