1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 10:18:11 +00:00

LibJS: Add spec comments to exp{,_double}()

This commit is contained in:
Linus Groh 2022-12-10 00:09:31 +00:00
parent eb4ea557f1
commit d74ce90e74

View file

@ -1875,69 +1875,137 @@ ThrowCompletionOr<Value> mod(VM& vm, Value lhs, Value rhs)
return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "modulo");
}
// 6.1.6.1.3 Number::exponentiate ( base, exponent ), https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate
static Value exp_double(Value base, Value exponent)
{
VERIFY(both_number(base, exponent));
// 1. If exponent is NaN, return NaN.
if (exponent.is_nan())
return js_nan();
// 2. If exponent is +0𝔽 or exponent is -0𝔽, return 1𝔽.
if (exponent.is_positive_zero() || exponent.is_negative_zero())
return Value(1);
// 3. If base is NaN, return NaN.
if (base.is_nan())
return js_nan();
if (base.is_positive_infinity())
// 4. If base is +∞𝔽, then
if (base.is_positive_infinity()) {
// a. If exponent > +0𝔽, return +∞𝔽. Otherwise, return +0𝔽.
return exponent.as_double() > 0 ? js_infinity() : Value(0);
}
// 5. If base is -∞𝔽, then
if (base.is_negative_infinity()) {
auto is_odd_integral_number = exponent.is_integral_number() && (static_cast<i32>(exponent.as_double()) % 2 != 0);
if (exponent.as_double() > 0)
// a. If exponent > +0𝔽, then
if (exponent.as_double() > 0) {
// i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
return is_odd_integral_number ? js_negative_infinity() : js_infinity();
else
}
// b. Else,
else {
// i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
return is_odd_integral_number ? Value(-0.0) : Value(0);
}
}
if (base.is_positive_zero())
// 6. If base is +0𝔽, then
if (base.is_positive_zero()) {
// a. If exponent > +0𝔽, return +0𝔽. Otherwise, return +∞𝔽.
return exponent.as_double() > 0 ? Value(0) : js_infinity();
}
// 7. If base is -0𝔽, then
if (base.is_negative_zero()) {
auto is_odd_integral_number = exponent.is_integral_number() && (static_cast<i32>(exponent.as_double()) % 2 != 0);
if (exponent.as_double() > 0)
// a. If exponent > +0𝔽, then
if (exponent.as_double() > 0) {
// i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
return is_odd_integral_number ? Value(-0.0) : Value(0);
else
}
// b. Else,
else {
// i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
return is_odd_integral_number ? js_negative_infinity() : js_infinity();
}
}
// 8. Assert: base is finite and is neither +0𝔽 nor -0𝔽.
VERIFY(base.is_finite_number() && !base.is_positive_zero() && !base.is_negative_zero());
// 9. If exponent is +∞𝔽, then
if (exponent.is_positive_infinity()) {
auto absolute_base = fabs(base.as_double());
// a. If abs((base)) > 1, return +∞𝔽.
if (absolute_base > 1)
return js_infinity();
// b. If abs((base)) is 1, return NaN.
else if (absolute_base == 1)
return js_nan();
// c. If abs((base)) < 1, return +0𝔽.
else if (absolute_base < 1)
return Value(0);
}
// 10. If exponent is -∞𝔽, then
if (exponent.is_negative_infinity()) {
auto absolute_base = fabs(base.as_double());
// a. If abs((base)) > 1, return +0𝔽.
if (absolute_base > 1)
return Value(0);
// b. If abs((base)) is 1, return NaN.
else if (absolute_base == 1)
return js_nan();
// a. If abs((base)) > 1, return +0𝔽.
else if (absolute_base < 1)
return js_infinity();
}
// 11. Assert: exponent is finite and is neither +0𝔽 nor -0𝔽.
VERIFY(exponent.is_finite_number() && !exponent.is_positive_zero() && !exponent.is_negative_zero());
// 12. If base < -0𝔽 and exponent is not an integral Number, return NaN.
if (base.as_double() < 0 && !exponent.is_integral_number())
return js_nan();
// 13. Return an implementation-approximated Number value representing the result of raising (base) to the (exponent) power.
return Value(::pow(base.as_double(), exponent.as_double()));
}
// 13.6 Exponentiation Operator, https://tc39.es/ecma262/#sec-exp-operator
// ExponentiationExpression : UpdateExpression ** ExponentiationExpression
ThrowCompletionOr<Value> exp(VM& vm, Value lhs, Value rhs)
{
// 3. Let lnum be ? ToNumeric(lval).
auto lhs_numeric = TRY(lhs.to_numeric(vm));
// 4. Let rnum be ? ToNumeric(rval).
auto rhs_numeric = TRY(rhs.to_numeric(vm));
if (both_number(lhs_numeric, rhs_numeric))
// 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table:
// [...]
// 8. Return operation(lnum, rnum).
if (both_number(lhs_numeric, rhs_numeric)) {
return exp_double(lhs_numeric, rhs_numeric);
}
if (both_bigint(lhs_numeric, rhs_numeric)) {
if (rhs_numeric.as_bigint().big_integer().is_negative())
// 6.1.6.2.3 BigInt::exponentiate ( base, exponent ), https://tc39.es/ecma262/#sec-numeric-types-bigint-exponentiate
auto base = lhs_numeric.as_bigint().big_integer();
auto exponent = rhs_numeric.as_bigint().big_integer();
// 1. If exponent < 0, throw a RangeError exception.
if (exponent.is_negative())
return vm.throw_completion<RangeError>(ErrorType::NegativeExponent);
return BigInt::create(vm, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer()));
// 2. If base is 0 and exponent is 0, return 1.
// 3. Return the BigInt value that represents (base) raised to the power (exponent).
return BigInt::create(vm, Crypto::NumberTheory::Power(base, exponent));
}
return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "exponentiation");
}