mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 896264 - Implement Math.hypot(). r=jorendorff.
This commit is contained in:
parent
48c3f090ac
commit
58587971d6
@ -1273,74 +1273,41 @@ js::math_atanh(JSContext *cx, unsigned argc, Value *vp)
|
||||
return math_function<math_atanh_impl>(cx, argc, vp);
|
||||
}
|
||||
|
||||
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
|
||||
#if 0
|
||||
#if !HAVE_HYPOT
|
||||
double hypot(double x, double y)
|
||||
{
|
||||
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y))
|
||||
return PositiveInfinity();
|
||||
|
||||
if (mozilla::IsNaN(x) || mozilla::IsNaN(y))
|
||||
return GenericNaN();
|
||||
|
||||
double xabs = mozilla::Abs(x);
|
||||
double yabs = mozilla::Abs(y);
|
||||
|
||||
double min = std::min(xabs, yabs);
|
||||
double max = std::max(xabs, yabs);
|
||||
|
||||
if (min == 0) {
|
||||
return max;
|
||||
} else {
|
||||
double u = min / max;
|
||||
return max * sqrt(1 + u * u);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
double
|
||||
js::math_hypot_impl(double x, double y)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
// On Windows, hypot(NaN, Infinity) is NaN. ES6 requires Infinity.
|
||||
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y))
|
||||
return PositiveInfinity();
|
||||
#endif
|
||||
return hypot(x, y);
|
||||
}
|
||||
|
||||
bool
|
||||
js::math_hypot(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() < 2) {
|
||||
args.rval().setNumber(GenericNaN());
|
||||
return true;
|
||||
|
||||
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))
|
||||
return false;
|
||||
|
||||
isInfinite |= mozilla::IsInfinite(x);
|
||||
isNaN |= mozilla::IsNaN(x);
|
||||
|
||||
double xabs = mozilla::Abs(x);
|
||||
|
||||
if (scale < xabs) {
|
||||
sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
|
||||
scale = xabs;
|
||||
} else if (scale != 0) {
|
||||
sumsq += (xabs / scale) * (xabs / scale);
|
||||
}
|
||||
}
|
||||
|
||||
double x, y;
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
if (!ToNumber(cx, args[1], &y))
|
||||
return false;
|
||||
|
||||
if (args.length() == 2) {
|
||||
args.rval().setNumber(math_hypot_impl(x, y));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* args.length() > 2 */
|
||||
double z;
|
||||
if (!ToNumber(cx, args[2], &z)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setNumber(math_hypot_impl(math_hypot_impl(x, y), z));
|
||||
double result = isInfinite ? PositiveInfinity() :
|
||||
isNaN ? GenericNaN() :
|
||||
scale * sqrt(sumsq);
|
||||
args.rval().setNumber(result);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_TRUNC
|
||||
double trunc(double x)
|
||||
@ -1468,10 +1435,7 @@ static const JSFunctionSpec math_static_methods[] = {
|
||||
JS_FN("acosh", math_acosh, 1, 0),
|
||||
JS_FN("asinh", math_asinh, 1, 0),
|
||||
JS_FN("atanh", math_atanh, 1, 0),
|
||||
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
|
||||
#if 0
|
||||
JS_FN("hypot", math_hypot, 2, 0),
|
||||
#endif
|
||||
JS_FN("trunc", math_trunc, 1, 0),
|
||||
JS_FN("sign", math_sign, 1, 0),
|
||||
JS_FN("cbrt", math_cbrt, 1, 0),
|
||||
|
@ -162,11 +162,8 @@ math_asinh(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
extern bool
|
||||
math_atanh(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
|
||||
#if 0
|
||||
extern bool
|
||||
math_hypot(JSContext *cx, unsigned argc, Value *vp);
|
||||
#endif
|
||||
|
||||
extern bool
|
||||
math_trunc(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
@ -1,14 +1,23 @@
|
||||
// |reftest| skip
|
||||
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
|
||||
|
||||
for (var i = -20; i < 20; i++) {
|
||||
assertEq(Math.hypot(+0, i), Math.abs(i));
|
||||
assertEq(Math.hypot(-0, i), Math.abs(i));
|
||||
}
|
||||
|
||||
assertNear(Math.hypot(1e300, 1e300), 1.4142135623730952e+300);
|
||||
// The implementation must avoid underlow.
|
||||
// The implementation must avoid overflow, where possible.
|
||||
// The implementation must minimise rounding errors.
|
||||
|
||||
assertNear(Math.hypot(1e-300, 1e-300), 1.414213562373095e-300);
|
||||
assertNear(Math.hypot(1e-300, 1e-300, 1e-300), 1.732050807568877e-300);
|
||||
|
||||
assertNear(Math.hypot(1e-3, 1e-3, 1e-3), 0.0017320508075688772);
|
||||
|
||||
assertNear(Math.hypot(1e300, 1e300), 1.4142135623730952e+300);
|
||||
assertNear(Math.hypot(1e100, 1e200, 1e300), 1e300);
|
||||
|
||||
assertNear(Math.hypot(1e3, 1e-3), 1000.0000000005);
|
||||
assertNear(Math.hypot(1e-300, 1e300), 1e300);
|
||||
assertNear(Math.hypot(1e3, 1e-3, 1e3, 1e-3), 1414.2135623738021555);
|
||||
|
||||
for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
|
||||
assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
|
||||
|
@ -1,8 +1,8 @@
|
||||
// |reftest| skip
|
||||
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
|
||||
|
||||
// Properties of Math.hypot that are guaranteed by the spec.
|
||||
|
||||
// If no arguments are passed, the result is +0.
|
||||
assertEq(Math.hypot(), +0);
|
||||
|
||||
// If any argument is +∞, the result is +∞.
|
||||
// If any argument is −∞, the result is +∞.
|
||||
for (var inf of [Infinity, -Infinity]) {
|
||||
@ -31,8 +31,7 @@ for (var inf of [Infinity, -Infinity]) {
|
||||
}
|
||||
|
||||
// If no argument is +∞ or −∞, and any argument is NaN, the result is NaN.
|
||||
assertEq(Math.hypot(), NaN);
|
||||
assertEq(Math.hypot(1), NaN);
|
||||
assertEq(Math.hypot(NaN), NaN);
|
||||
|
||||
assertEq(Math.hypot(NaN, 0), NaN);
|
||||
assertEq(Math.hypot(0, NaN), NaN);
|
||||
|
Loading…
Reference in New Issue
Block a user