/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using JS::GenericNaN; using JS::ToNumber; using mozilla::ExponentComponent; using mozilla::FloatingPoint; using mozilla::IsNegative; using mozilla::IsNegativeZero; using mozilla::Maybe; using mozilla::NegativeInfinity; using mozilla::NumberEqualsInt32; using mozilla::NumberEqualsInt64; using mozilla::PositiveInfinity; using mozilla::WrappingMultiply;
double x; if (!ToNumber(cx, args[0], &x)) { returnfalse;
}
// TODO(post-Warp): Re-evaluate if it's still necessary resp. useful to always // type the value as a double.
// NB: Always stored as a double so the math function can be inlined // through MMathFunction. double z = F(x);
args.rval().setDouble(z); returntrue;
}
// 1. Let n be ? ToNumber(x). // [Not applicable here]
// 2. If n is NaN, return NaN. // 3. If n is one of +0, -0, +∞, or -∞, return n. // 4. Let n16 be the result of converting n to IEEE 754-2019 binary16 format // using roundTiesToEven mode.
js::float16 f16 = js::float16(d);
// 5. Let n64 be the result of converting n16 to IEEE 754-2019 binary64 // format. // 6. Return the ECMAScript Number value corresponding to n64. returnstatic_cast<double>(f16);
}
// It's only safe to optimize this when we can compute with integer values or // the exponent is a small, positive constant. if (y >= 0) {
uint32_t n = uint32_t(y);
// NB: Have to take fast-path for n <= 4 to match |MPow::foldsTo|. Otherwise // we risk causing differential testing issues. if (n == 0) { return 1;
} if (n == 1) { return x;
} if (n == 2) { return x * x;
} if (n == 3) { return x * x * x;
} if (n == 4) { double z = x * x; return z * z;
}
int64_t i; if (NumberEqualsInt64(x, &i)) { // Special-case: |-0 ** odd| is -0. if (i == 0) { return (n & 1) ? x : 0;
}
// Use int64 to cover cases like |Math.pow(2, 53)|.
mozilla::CheckedInt64 runningSquare = i;
mozilla::CheckedInt64 result = 1; while (true) { if ((n & 1) != 0) {
result *= runningSquare; if (!result.isValid()) { break;
}
}
n >>= 1; if (n == 0) { returnstatic_cast<double>(result.value());
}
runningSquare *= runningSquare; if (!runningSquare.isValid()) { break;
}
}
}
// Fall-back to use std::pow to reduce floating point precision errors.
}
/* * Use powi if the exponent is an integer-valued double. We don't have to * check for NaN since a comparison with NaN is always false.
*/
int32_t yi; if (NumberEqualsInt32(y, &yi)) { return powi(x, yi);
}
/* * Because C99 and ECMA specify different behavior for pow(), * we need to wrap the libm call to make it ECMA compliant.
*/ if (!std::isfinite(y) && (x == 1.0 || x == -1.0)) { return GenericNaN();
}
/* pow(x, +-0) is always 1, even for x = NaN (MSVC gets this wrong). */ if (y == 0) { return 1;
}
/* * Special case for square roots. Note that pow(x, 0.5) != sqrt(x) * when x = -0.0, so we have to guard for this.
*/ if (std::isfinite(x) && x != 0.0) { if (y == 0.5) { return std::sqrt(x);
} if (y == -0.5) { return 1.0 / std::sqrt(x);
}
} return std::pow(x, y);
}
return maybeSeed.valueOrFrom([] { // Use PRMJ_Now() in case we couldn't read random bits from the OS.
uint64_t timestamp = PRMJ_Now(); return timestamp ^ (timestamp << 32);
});
}
void js::GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed) { // XorShift128PlusRNG must be initialized with a non-zero seed. do {
seed[0] = GenerateRandomSeed();
seed[1] = GenerateRandomSeed();
} while (seed[0] == 0 && seed[1] == 0);
}
int32_t ignored; if (NumberEqualsInt32(x, &ignored)) { return x;
}
/* Some numbers are so big that adding 0.5 would give the wrong number. */ if (ExponentComponent(x) >=
int_fast16_t(FloatingPoint<double>::kExponentShift)) { return x;
}
int32_t ignored; if (NumberEqualsInt32(x, &ignored)) { return x;
}
/* Some numbers are so big that adding 0.5 would give the wrong number. */ if (ExponentComponent(x) >=
int_fast16_t(FloatingPoint<float>::kExponentShift)) { return x;
}
// Check for infinities or NaNs so that we can return immediately. if (std::isinf(x) || std::isinf(y) || std::isinf(z) || std::isinf(w)) { return mozilla::PositiveInfinity<double>();
}
bool js::math_hypot_handle(JSContext* cx, HandleValueArray args,
MutableHandleValue res) { // IonMonkey calls the ecmaHypot function directly if two arguments are // given. Do that here as well to get the same results. if (args.length() == 2) { double x, y; if (!ToNumber(cx, args[0], &x)) { returnfalse;
} if (!ToNumber(cx, args[1], &y)) { returnfalse;
}
double result = ecmaHypot(x, y);
res.setDouble(result); returntrue;
}
bool isInfinite = false; bool isNaN = false;
double scale = 0; double sumsq = 1;
for (unsigned i = 0; i < args.length(); i++) { double x; if (!ToNumber(cx, args[i], &x)) { returnfalse;
}
// Step 2. Let iteratorRecord be ? GetIterator(items, sync).
JS::ForOfIterator iterator(cx); if (!iterator.init(args[0], JS::ForOfIterator::ThrowOnNonIterable)) { returnfalse;
}
// Step 3. Let state be minus-zero.
SumPreciseState state = SumPreciseState::MinusZero;
// Step 4. Let sum be 0.
xsum_small_accumulator sum;
xsum_small_init(&sum);
// Step 5. Let count be 0.
int64_t count = 0;
// Step 6. Let next be not-started. // (implicit)
JS::Rooted<JS::Value> value(cx);
// Step 7. Repeat, while next is not done, while (true) { // Step 7.a. Set next to ? IteratorStepValue(iteratorRecord). bool done; if (!iterator.next(&value, &done)) { returnfalse;
}
// Step 7.b. If next is not done, then if (done) { break;
}
// Step 7.b.i. Set count to count + 1.
count += 1;
// Step 7.b.ii. If count ≥ 2**53, then if (count >= MaxCount) { // Step 7.b.ii.1. Let error be ThrowCompletion(a newly created RangeError // object).
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SUMPRECISE_TOO_MANY_VALUES);
// Step 7.b.iv. If next is not a Number, then if (!value.isNumber()) { // Step 7.b.iv.1. Let error be ThrowCompletion(a newly created TypeError // object).
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SUMPRECISE_EXPECTED_NUMBER);
// Step 7.b.v. Let n be next. double n = value.toNumber();
// Step 7.b.vi. If state is not not-a-number, then if (state == SumPreciseState::NotANumber) { continue;
}
// Step 7.b.vi.1. If n is NaN, then if (std::isnan(n)) { // Step 7.b.vi.1.a. Set state to not-a-number.
state = SumPreciseState::NotANumber;
} elseif (n == PositiveInfinity<double>()) { // Step 7.b.vi.2. Else if n is +∞, then if (state == SumPreciseState::MinusInfinity) { // Step 7.b.vi.2.a. If state is minus-infinity, set state to // not-a-number.
state = SumPreciseState::NotANumber;
} else { // Step 7.b.vi.2.b. Else, set state to plus-infinity.
state = SumPreciseState::PlusInfinity;
}
} elseif (n == NegativeInfinity<double>()) { // Step 7.b.vi.3. Else if n is -∞, then if (state == SumPreciseState::PlusInfinity) { // Step 7.b.vi.3.a. If state is plus-infinity, set state to // not-a-number.
state = SumPreciseState::NotANumber;
} else { // Step 7.b.vi.3.b. Else, set state to minus-infinity.
state = SumPreciseState::MinusInfinity;
}
} elseif (!IsNegativeZero(n) && (state == SumPreciseState::MinusZero ||
state == SumPreciseState::Finite)) { // Step 7.b.vi.4. Else if n is not -0 and state is either minus-zero or // finite, then // Step 7.b.vi.4.a. Set state to finite.
state = SumPreciseState::Finite;
// Step 7.b.vi.4.b. Set sum to sum + ℝ(n).
xsum_small_add1(&sum, n);
}
}
double rval; switch (state) { case SumPreciseState::NotANumber: // Step 8. If state is not-a-number, return NaN.
rval = GenericNaN(); break; case SumPreciseState::PlusInfinity: // Step 9. If state is plus-infinity, return +∞.
rval = PositiveInfinity<double>(); break; case SumPreciseState::MinusInfinity: // Step 10. If state is minus-infinity, return -∞.
rval = NegativeInfinity<double>(); break; case SumPreciseState::MinusZero: // Step 11. If state is minus-zero, return -0.
rval = -0.0; break; case SumPreciseState::Finite: // Step 12. Return (sum).
rval = xsum_small_round(&sum); break;
}
args.rval().setNumber(rval); returntrue;
} #endif
UnaryMathFunctionType js::GetUnaryMathFunctionPtr(UnaryMathFunction fun) { switch (fun) { case UnaryMathFunction::SinNative: return math_sin_native_impl; case UnaryMathFunction::SinFdlibm: return math_sin_fdlibm_impl; case UnaryMathFunction::CosNative: return math_cos_native_impl; case UnaryMathFunction::CosFdlibm: return math_cos_fdlibm_impl; case UnaryMathFunction::TanNative: return math_tan_native_impl; case UnaryMathFunction::TanFdlibm: return math_tan_fdlibm_impl; case UnaryMathFunction::Log: return math_log_impl; case UnaryMathFunction::Exp: return math_exp_impl; case UnaryMathFunction::ATan: return math_atan_impl; case UnaryMathFunction::ASin: return math_asin_impl; case UnaryMathFunction::ACos: return math_acos_impl; case UnaryMathFunction::Log10: return math_log10_impl; case UnaryMathFunction::Log2: return math_log2_impl; case UnaryMathFunction::Log1P: return math_log1p_impl; case UnaryMathFunction::ExpM1: return math_expm1_impl; case UnaryMathFunction::CosH: return math_cosh_impl; case UnaryMathFunction::SinH: return math_sinh_impl; case UnaryMathFunction::TanH: return math_tanh_impl; case UnaryMathFunction::ACosH: return math_acosh_impl; case UnaryMathFunction::ASinH: return math_asinh_impl; case UnaryMathFunction::ATanH: return math_atanh_impl; case UnaryMathFunction::Trunc: return math_trunc_impl; case UnaryMathFunction::Cbrt: return math_cbrt_impl; case UnaryMathFunction::Floor: return math_floor_impl; case UnaryMathFunction::Ceil: return math_ceil_impl; case UnaryMathFunction::Round: return math_round_impl;
}
MOZ_CRASH("Unknown function");
}
constchar* js::GetUnaryMathFunctionName(UnaryMathFunction fun, bool enumName) { switch (fun) { case UnaryMathFunction::SinNative: return enumName ? "SinNative" : "Sin (native)"; case UnaryMathFunction::SinFdlibm: return enumName ? "SinFdlibm" : "Sin (fdlibm)"; case UnaryMathFunction::CosNative: return enumName ? "CosNative" : "Cos (native)"; case UnaryMathFunction::CosFdlibm: return enumName ? "CosFdlibm" : "Cos (fdlibm)"; case UnaryMathFunction::TanNative: return enumName ? "TanNative" : "Tan (native)"; case UnaryMathFunction::TanFdlibm: return enumName ? "TanFdlibm" : "Tan (fdlibm)"; case UnaryMathFunction::Log: return"Log"; case UnaryMathFunction::Exp: return"Exp"; case UnaryMathFunction::ACos: return"ACos"; case UnaryMathFunction::ASin: return"ASin"; case UnaryMathFunction::ATan: return"ATan"; case UnaryMathFunction::Log10: return"Log10"; case UnaryMathFunction::Log2: return"Log2"; case UnaryMathFunction::Log1P: return"Log1P"; case UnaryMathFunction::ExpM1: return"ExpM1"; case UnaryMathFunction::CosH: return"CosH"; case UnaryMathFunction::SinH: return"SinH"; case UnaryMathFunction::TanH: return"TanH"; case UnaryMathFunction::ACosH: return"ACosH"; case UnaryMathFunction::ASinH: return"ASinH"; case UnaryMathFunction::ATanH: return"ATanH"; case UnaryMathFunction::Trunc: return"Trunc"; case UnaryMathFunction::Cbrt: return"Cbrt"; case UnaryMathFunction::Floor: return"Floor"; case UnaryMathFunction::Ceil: return"Ceil"; case UnaryMathFunction::Round: return"Round";
}
MOZ_CRASH("Unknown function");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.