author | David Caabeiro <david.caabeiro@gmail.com> |
Wed, 02 Oct 2013 17:27:50 +0200 | |
changeset 151878 | eafe6b0acd33631cedf91cfe2f6245ea634bf2f9 |
parent 151877 | 9f4815b4ad647f0724fb9ec5a794031817a998aa |
child 151879 | 35a83682c173c50c54901ccb5781448d2f66cc99 |
push id | 25512 |
push user | cbook@mozilla.com |
push date | Thu, 24 Oct 2013 05:06:01 +0000 |
treeherder | autoland@19fd3388c372 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jorendorff |
bugs | 896264 |
milestone | 27.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -1268,84 +1268,51 @@ js::math_atanh_uncached(double x) } bool 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) { return x > 0 ? floor(x) : ceil(x); } #endif @@ -1463,20 +1430,17 @@ static const JSFunctionSpec math_static_ JS_FN("log1p", math_log1p, 1, 0), JS_FN("expm1", math_expm1, 1, 0), JS_FN("cosh", math_cosh, 1, 0), JS_FN("sinh", math_sinh, 1, 0), JS_FN("tanh", math_tanh, 1, 0), 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), JS_FS_END }; JSObject * js_InitMathClass(JSContext *cx, HandleObject obj)
--- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -157,21 +157,18 @@ extern bool math_acosh(JSContext *cx, unsigned argc, js::Value *vp); extern bool 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); extern bool math_sign(JSContext *cx, unsigned argc, Value *vp); extern bool
--- a/js/src/tests/ecma_6/Math/hypot-approx.js +++ b/js/src/tests/ecma_6/Math/hypot-approx.js @@ -1,16 +1,25 @@ -// |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)); reportCompare(0, 0, "ok");
--- a/js/src/tests/ecma_6/Math/hypot-exact.js +++ b/js/src/tests/ecma_6/Math/hypot-exact.js @@ -1,12 +1,12 @@ -// |reftest| skip -// Math.hypot is disabled pending the resolution of spec issues (bug 896264). +// Properties of Math.hypot that are guaranteed by the spec. -// 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]) { assertEq(Math.hypot(inf, 0), Infinity); assertEq(Math.hypot(0, inf), Infinity); assertEq(Math.hypot(inf, inf), Infinity); assertEq(Math.hypot(inf, -inf), Infinity); @@ -26,18 +26,17 @@ for (var inf of [Infinity, -Infinity]) { assertEq(Math.hypot(NaN, inf), Infinity); assertEq(Math.hypot(inf, NaN, NaN), Infinity); assertEq(Math.hypot(NaN, inf, NaN), Infinity); assertEq(Math.hypot(NaN, NaN, inf), 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); assertEq(Math.hypot(NaN, NaN), NaN); assertEq(Math.hypot(NaN, 0, 0), NaN); assertEq(Math.hypot(0, NaN, 0), NaN);