Implement Math.hypot
https://bugs.webkit.org/show_bug.cgi?id=129486
Patch by Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com> on 2014-03-17
Reviewed by Darin Adler.
Source/JavaScriptCore:
* runtime/MathObject.cpp:
(JSC::MathObject::finishCreation):
(JSC::mathProtoFuncHypot):
LayoutTests:
* js/Object-getOwnPropertyNames-expected.txt:
* js/math-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/math.js:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@165795 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index fd688e7..99a00a7 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
+2014-03-17 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com>
+
+ Implement Math.hypot
+ https://bugs.webkit.org/show_bug.cgi?id=129486
+
+ Reviewed by Darin Adler.
+
+ * js/Object-getOwnPropertyNames-expected.txt:
+ * js/math-expected.txt:
+ * js/script-tests/Object-getOwnPropertyNames.js:
+ * js/script-tests/math.js:
+
2014-03-17 Jer Noble <jer.noble@apple.com>
Layout Test mathml/wbr-in-mroot-crash.html crashes
diff --git a/LayoutTests/js/Object-getOwnPropertyNames-expected.txt b/LayoutTests/js/Object-getOwnPropertyNames-expected.txt
index 764a921..20044cc 100644
--- a/LayoutTests/js/Object-getOwnPropertyNames-expected.txt
+++ b/LayoutTests/js/Object-getOwnPropertyNames-expected.txt
@@ -58,7 +58,7 @@
PASS getSortedOwnPropertyNames(RegExp.prototype) is ['compile', 'constructor', 'exec', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'test', 'toString']
PASS getSortedOwnPropertyNames(Error) is ['length', 'name', 'prototype']
PASS getSortedOwnPropertyNames(Error.prototype) is ['constructor', 'message', 'name', 'toString']
-PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','cos','cosh','exp','expm1','floor','fround','imul','log','log10','log1p','log2','max','min','pow','random','round','sin','sinh','sqrt','tan','tanh','trunc']
+PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sin','sinh','sqrt','tan','tanh','trunc']
PASS getSortedOwnPropertyNames(JSON) is ['parse', 'stringify']
PASS globalPropertyNames.indexOf('NaN') != -1 is true
PASS globalPropertyNames.indexOf('Infinity') != -1 is true
diff --git a/LayoutTests/js/math-expected.txt b/LayoutTests/js/math-expected.txt
index 827088f..246e986 100644
--- a/LayoutTests/js/math-expected.txt
+++ b/LayoutTests/js/math-expected.txt
@@ -83,6 +83,29 @@
PASS Math.floor(-Number.MAX_VALUE) is -Number.MAX_VALUE
PASS Math.floor(Infinity) is Infinity
PASS Math.floor(-Infinity) is -Infinity
+PASS Math.hypot.length is 2
+PASS Math.hypot(NaN) is NaN
+PASS Math.hypot() is 0
+PASS Math.hypot(-0) is 0
+PASS Math.hypot(0) is 0
+PASS Math.hypot(-Infinity) is Infinity
+PASS Math.hypot(Infinity) is Infinity
+PASS Math.hypot(-3) is 3
+PASS Math.hypot(3, 4) is 5
+PASS Math.hypot(1, NaN, Infinity) is Infinity
+PASS Math.hypot(3, 4, 5) is 7.0710678118654755
+PASS Math.hypot(3, 4, '5') is 7.0710678118654755
+PASS Math.hypot(-3, -4) is 5
+PASS Math.hypot(3, -Infinity) is Infinity
+PASS Math.hypot(3, NaN) is NaN
+PASS Math.hypot(NaN, 3) is NaN
+PASS Math.hypot(0, NaN) is NaN
+PASS Math.hypot(NaN, 0) is NaN
+PASS Math.hypot(NaN, {valueOf:function(){throw "err"}}) threw exception err.
+PASS Math.hypot(NaN, NaN, {valueOf:function(){throw "err"}}) threw exception err.
+PASS Math.hypot({valueOf:function(){throw "error1"}}, {valueOf:function(){sideEffect = 1}}) threw exception error1.
+PASS sideEffect is 0
+PASS Math.hypot(3, 4, 'foo') is NaN
PASS Math.log(NaN) is NaN
PASS Math.log(0) is -Infinity
PASS Math.log(-0) is -Infinity
diff --git a/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js b/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
index 99c4e39..dc90250 100644
--- a/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
+++ b/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js
@@ -66,7 +66,7 @@
"RegExp.prototype": "['compile', 'constructor', 'exec', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'test', 'toString']",
"Error": "['length', 'name', 'prototype']",
"Error.prototype": "['constructor', 'message', 'name', 'toString']",
- "Math": "['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','cos','cosh','exp','expm1','floor','fround','imul','log','log10','log1p','log2','max','min','pow','random','round','sin','sinh','sqrt','tan','tanh','trunc']",
+ "Math": "['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sin','sinh','sqrt','tan','tanh','trunc']",
"JSON": "['parse', 'stringify']"
};
diff --git a/LayoutTests/js/script-tests/math.js b/LayoutTests/js/script-tests/math.js
index 943fb68..44aae05 100644
--- a/LayoutTests/js/script-tests/math.js
+++ b/LayoutTests/js/script-tests/math.js
@@ -124,6 +124,31 @@
shouldBe("Math.floor(Infinity)", "Infinity");
shouldBe("Math.floor(-Infinity)", "-Infinity");
+shouldBe("Math.hypot.length","2");
+shouldBe("Math.hypot(NaN)", "NaN");
+shouldBe("Math.hypot()", "0");
+shouldBe("Math.hypot(-0)", "0");
+shouldBe("Math.hypot(0)", "0");
+shouldBe("Math.hypot(-Infinity)", "Infinity");
+shouldBe("Math.hypot(Infinity)", "Infinity");
+shouldBe("Math.hypot(-3)", "3");
+shouldBe("Math.hypot(3, 4)", "5");
+shouldBe("Math.hypot(1, NaN, Infinity)", "Infinity");
+shouldBe("Math.hypot(3, 4, 5)", "7.0710678118654755");
+shouldBe("Math.hypot(3, 4, '5')", "7.0710678118654755");
+shouldBe("Math.hypot(-3, -4)", "5");
+shouldBe("Math.hypot(3, -Infinity)", "Infinity");
+shouldBe("Math.hypot(3, NaN)", "NaN");
+shouldBe("Math.hypot(NaN, 3)", "NaN");
+shouldBe("Math.hypot(0, NaN)", "NaN");
+shouldBe("Math.hypot(NaN, 0)", "NaN");
+shouldThrow("Math.hypot(NaN, {valueOf:function(){throw \"err\"}})","'err'");
+shouldThrow("Math.hypot(NaN, NaN, {valueOf:function(){throw \"err\"}})","'err'");
+sideEffect = 0;
+shouldThrow("Math.hypot({valueOf:function(){throw \"error1\"}}, {valueOf:function(){sideEffect = 1}})", "'error1'");
+shouldBe('sideEffect', '0');
+shouldBe("Math.hypot(3, 4, 'foo')", "NaN");
+
shouldBe("Math.log(NaN)", "NaN");
shouldBe("Math.log(0)", "-Infinity");
shouldBe("Math.log(-0)", "-Infinity");
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index d7b6c58..5025163 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,14 @@
+2014-03-17 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com>
+
+ Implement Math.hypot
+ https://bugs.webkit.org/show_bug.cgi?id=129486
+
+ Reviewed by Darin Adler.
+
+ * runtime/MathObject.cpp:
+ (JSC::MathObject::finishCreation):
+ (JSC::mathProtoFuncHypot):
+
2014-03-17 Zsolt Borbely <borbezs@inf.u-szeged.hu>
Fix the !ENABLE(PROMISES) build
diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp
index f671ace9..d600c92 100644
--- a/Source/JavaScriptCore/runtime/MathObject.cpp
+++ b/Source/JavaScriptCore/runtime/MathObject.cpp
@@ -29,6 +29,7 @@
#include <wtf/MathExtras.h>
#include <wtf/RandomNumber.h>
#include <wtf/RandomNumberSeed.h>
+#include <wtf/Vector.h>
namespace JSC {
@@ -50,6 +51,7 @@
static EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState*);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState*);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState*);
static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState*);
@@ -108,6 +110,7 @@
putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum | Function);
putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum | Function);
putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "fround"), 1, mathProtoFuncFround, NoIntrinsic, DontEnum | Function);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "hypot"), 2, mathProtoFuncHypot, NoIntrinsic, DontEnum | Function);
putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum | Function);
putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum | Function);
putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum | Function);
@@ -175,6 +178,35 @@
return JSValue::encode(jsNumber(floor(exec->argument(0).toNumber(exec))));
}
+EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState* exec)
+{
+ unsigned argsCount = exec->argumentCount();
+ double max = 0;
+ Vector<double, 8> args;
+ args.reserveInitialCapacity(argsCount);
+ for (unsigned i = 0; i < argsCount; ++i) {
+ args.uncheckedAppend(exec->uncheckedArgument(i).toNumber(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ if (std::isinf(args[i]))
+ return JSValue::encode(jsDoubleNumber(+std::numeric_limits<double>::infinity()));
+ max = std::max(fabs(args[i]), max);
+ }
+ if (!max)
+ max = 1;
+ // Kahan summation algorithm significantly reduces the numerical error in the total obtained.
+ double sum = 0;
+ double compensation = 0;
+ for (double argument : args) {
+ double scaledArgument = argument / max;
+ double summand = scaledArgument * scaledArgument - compensation;
+ double preliminary = sum + summand;
+ compensation = (preliminary - sum) - summand;
+ sum = preliminary;
+ }
+ return JSValue::encode(jsDoubleNumber(sqrt(sum) * max));
+}
+
EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec)
{
return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec))));