blob: 0898c69c9867bc288c262d7d7885fefa662f1dcf [file] [log] [blame]
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/counters.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 20.2.2 Function Properties of the Math Object
// 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::kZero;
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(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->heap()->nan_value();
}
if (max == 0) {
return Smi::kZero;
}
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);
}
} // namespace internal
} // namespace v8