[math] Fix Math.hypot to properly call ToNumber on all arguments.

The spec requires all Math functions to first call ToNumber on all
arguments before doing any other observable operation.  So early
return in case of Infinity is not valid.

Drive-by-fix: Remove the use of %_Arguments / %_ArgumentsLength and
use (strict) arguments instead of allocating a temporary InternalArray
explicitly.

R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/1669773002

Cr-Commit-Position: refs/heads/master@{#33717}
This commit is contained in:
bmeurer 2016-02-03 23:22:39 -08:00 committed by Commit bot
parent db74cccf8a
commit 264fa75e52
2 changed files with 12 additions and 8 deletions

View File

@ -164,17 +164,14 @@ function MathHypot(x, y) { // Function length is 2.
// We may want to introduce fast paths for two arguments and when
// normalization to avoid overflow is not necessary. For now, we
// simply assume the general case.
var length = %_ArgumentsLength();
var args = new InternalArray(length);
var length = arguments.length;
var max = 0;
for (var i = 0; i < length; i++) {
var n = %_Arguments(i);
n = TO_NUMBER(n);
if (n === INFINITY || n === -INFINITY) return INFINITY;
n = MathAbs(n);
var n = MathAbs(arguments[i]);
if (n > max) max = n;
args[i] = n;
arguments[i] = n;
}
if (max === INFINITY) return INFINITY;
// Kahan summation to avoid rounding errors.
// Normalize the numbers to the largest one to avoid overflow.
@ -182,7 +179,7 @@ function MathHypot(x, y) { // Function length is 2.
var sum = 0;
var compensation = 0;
for (var i = 0; i < length; i++) {
var n = args[i] / max;
var n = arguments[i] / max;
var summand = n * n - compensation;
var preliminary = sum + summand;
compensation = (preliminary - sum) - summand;

View File

@ -56,6 +56,13 @@ x = "";
assertEquals(1, Math.pow(v, w));
assertEquals("hestfisk", x, "pow");
x = "";
var a = {valueOf: function() { x += "hest"; return 1/0; }};
var b = {valueOf: function() { x += "fisk"; return 1}};
assertEquals(1/0, Math.hypot(a, b));
assertEquals("hestfisk", x, "hypot");
var year = { valueOf: function() { x += 1; return 2007; } };
var month = { valueOf: function() { x += 2; return 2; } };
var date = { valueOf: function() { x += 3; return 4; } };