summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Runtime/MathObject.cpp
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2021-06-05 02:53:30 +0300
committerLinus Groh <mail@linusgroh.de>2021-06-05 14:56:58 +0100
commit03255c1c53bcdb45959ef67b6f4dcfb90503d0d8 (patch)
treed9955cddcb13e6b6bacf82556e7d993e72404fcc /Userland/Libraries/LibJS/Runtime/MathObject.cpp
parent7507999230af65f6ab46c481f534c3778caa772e (diff)
downloadserenity-03255c1c53bcdb45959ef67b6f4dcfb90503d0d8.zip
LibJS: Handle NaN/Infinity/Zero edge cases in Math.pow()
This commit replaces the current simple call to LibM's pow with the full implementation of 6.1.6.1.3 Number::exponentiate: https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime/MathObject.cpp')
-rw-r--r--Userland/Libraries/LibJS/Runtime/MathObject.cpp54
1 files changed, 53 insertions, 1 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/MathObject.cpp b/Userland/Libraries/LibJS/Runtime/MathObject.cpp
index ac9e202175..b005d0fff6 100644
--- a/Userland/Libraries/LibJS/Runtime/MathObject.cpp
+++ b/Userland/Libraries/LibJS/Runtime/MathObject.cpp
@@ -235,7 +235,59 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::tan)
JS_DEFINE_NATIVE_FUNCTION(MathObject::pow)
{
- return JS::exp(global_object, vm.argument(0), vm.argument(1));
+ auto base = vm.argument(0).to_number(global_object);
+ if (vm.exception())
+ return {};
+ auto exponent = vm.argument(1).to_number(global_object);
+ if (vm.exception())
+ return {};
+ if (exponent.is_nan())
+ return js_nan();
+ if (exponent.is_positive_zero() || exponent.is_negative_zero())
+ return Value(1);
+ if (base.is_nan())
+ return js_nan();
+ if (base.is_positive_infinity())
+ return exponent.as_double() > 0 ? js_infinity() : Value(0);
+ if (base.is_negative_infinity()) {
+ auto is_odd_integral_number = exponent.is_integer() && (exponent.as_i32() % 2 != 0);
+ if (exponent.as_double() > 0)
+ return is_odd_integral_number ? js_negative_infinity() : js_infinity();
+ else
+ return is_odd_integral_number ? Value(-0.0) : Value(0);
+ }
+ if (base.is_positive_zero())
+ return exponent.as_double() > 0 ? Value(0) : js_infinity();
+ if (base.is_negative_zero()) {
+ auto is_odd_integral_number = exponent.is_integer() && (exponent.as_i32() % 2 != 0);
+ if (exponent.as_double() > 0)
+ return is_odd_integral_number ? Value(-0.0) : Value(0);
+ else
+ return is_odd_integral_number ? js_negative_infinity() : js_infinity();
+ }
+ VERIFY(base.is_finite_number() && !base.is_positive_zero() && !base.is_negative_zero());
+ if (exponent.is_positive_infinity()) {
+ auto absolute_base = fabs(base.as_double());
+ if (absolute_base > 1)
+ return js_infinity();
+ else if (absolute_base == 1)
+ return js_nan();
+ else if (absolute_base < 1)
+ return Value(0);
+ }
+ if (exponent.is_negative_infinity()) {
+ auto absolute_base = fabs(base.as_double());
+ if (absolute_base > 1)
+ return Value(0);
+ else if (absolute_base == 1)
+ return js_nan();
+ else if (absolute_base < 1)
+ return js_infinity();
+ }
+ VERIFY(exponent.is_finite_number() && !exponent.is_positive_zero() && !exponent.is_negative_zero());
+ if (base.as_double() < 0 && !exponent.is_integer())
+ return js_nan();
+ return Value(::pow(base.as_double(), exponent.as_double()));
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::exp)