Commit fe1a07fe authored by franzih's avatar franzih Committed by Commit bot

[builtins] Migrate Math.hypot() to C++ builtins.

Migrate Math.hypot() from JS to C++ builtins. Use normalization and
Kahan summation to avoid overflow and rounding errors.

R=bmeurer@chromium.org
BUG=v8:5165, v8:5086
LOG=n

Review-Url: https://codereview.chromium.org/2102223005
Cr-Commit-Position: refs/heads/master@{#37473}
parent 5a2f5c12
......@@ -1690,6 +1690,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleInstallFunction(math, "floor", Builtins::kMathFloor, 1, true);
native_context()->set_math_floor(*math_floor);
SimpleInstallFunction(math, "fround", Builtins::kMathFround, 1, true);
SimpleInstallFunction(math, "hypot", Builtins::kMathHypot, 2, false);
SimpleInstallFunction(math, "imul", Builtins::kMathImul, 2, true);
Handle<JSFunction> math_log =
SimpleInstallFunction(math, "log", Builtins::kMathLog, 1, true);
......
......@@ -2269,6 +2269,58 @@ BUILTIN(MathAsin) {
return *isolate->factory()->NewHeapNumber(std::asin(x->Number()));
}
// ES6 section 20.2.2.18 Math.hypot ( value1, value2, ...values )
BUILTIN(MathHypot) {
HandleScope scope(isolate);
int const length = args.length() - 1;
if (length == 0) return Smi::FromInt(0);
DCHECK_LT(0, length);
double max = 0;
bool one_arg_is_nan = false;
List<double> abs_values(length);
for (int i = 0; i < length; i++) {
Handle<Object> x = args.at<Object>(i + 1);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x));
double abs_value = std::abs(x->Number());
if (std::isnan(abs_value)) {
one_arg_is_nan = true;
} else {
abs_values.Add(abs_value);
if (max < abs_value) {
max = abs_value;
}
}
}
if (max == V8_INFINITY) {
return *isolate->factory()->NewNumber(V8_INFINITY);
}
if (one_arg_is_nan) {
return *isolate->factory()->nan_value();
}
if (max == 0) {
return Smi::FromInt(0);
}
DCHECK_GT(max, 0);
// Kahan summation to avoid rounding errors.
// Normalize the numbers to the largest one to avoid overflow.
double sum = 0;
double compensation = 0;
for (int i = 0; i < length; i++) {
double n = abs_values.at(i) / max;
double summand = n * n - compensation;
double preliminary = sum + summand;
compensation = (preliminary - sum) - summand;
sum = preliminary;
}
return *isolate->factory()->NewNumber(std::sqrt(sum) * max);
}
// ES6 section 20.2.2.6 Math.atan ( x )
void Builtins::Generate_MathAtan(CodeStubAssembler* assembler) {
using compiler::Node;
......
......@@ -120,6 +120,7 @@ class CodeStubAssembler;
V(MathAcos, BUILTIN_EXIT) \
V(MathAsin, BUILTIN_EXIT) \
V(MathFround, BUILTIN_EXIT) \
V(MathHypot, BUILTIN_EXIT) \
V(MathImul, BUILTIN_EXIT) \
\
V(ObjectAssign, BUILTIN_EXIT) \
......
......@@ -66,34 +66,6 @@ function MathAcosh(x) {
return %math_log(x + %math_sqrt(x + 1) * %math_sqrt(x - 1));
}
// ES6 draft 09-27-13, section 20.2.2.17.
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 = arguments.length;
var max = 0;
for (var i = 0; i < length; i++) {
var n = %math_abs(arguments[i]);
if (n > max) max = 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.
if (max === 0) max = 1;
var sum = 0;
var compensation = 0;
for (var i = 0; i < length; i++) {
var n = arguments[i] / max;
var summand = n * n - compensation;
var preliminary = sum + summand;
compensation = (preliminary - sum) - summand;
sum = preliminary;
}
return %math_sqrt(sum) * max;
}
// -------------------------------------------------------------------
......@@ -112,8 +84,7 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
"random", MathRandom,
"sign", MathSign,
"asinh", MathAsinh,
"acosh", MathAcosh,
"hypot", MathHypot,
"acosh", MathAcosh
]);
%SetForceInlineFlag(MathRandom);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment