Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/builtins/builtins-utils.h"
6 : #include "src/builtins/builtins.h"
7 : #include "src/counters.h"
8 : #include "src/objects-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 : // -----------------------------------------------------------------------------
14 : // ES6 section 20.2.2 Function Properties of the Math Object
15 :
16 : // ES6 section 20.2.2.18 Math.hypot ( value1, value2, ...values )
17 1440 : BUILTIN(MathHypot) {
18 : HandleScope scope(isolate);
19 288 : int const length = args.length() - 1;
20 288 : if (length == 0) return Smi::kZero;
21 : DCHECK_LT(0, length);
22 : double max = 0;
23 : bool one_arg_is_nan = false;
24 : std::vector<double> abs_values;
25 252 : abs_values.reserve(length);
26 15912 : for (int i = 0; i < length; i++) {
27 7830 : Handle<Object> x = args.at(i + 1);
28 15660 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
29 : Object::ToNumber(isolate, x));
30 7830 : double abs_value = std::abs(x->Number());
31 :
32 7830 : if (std::isnan(abs_value)) {
33 : one_arg_is_nan = true;
34 : } else {
35 7758 : abs_values.push_back(abs_value);
36 7758 : if (max < abs_value) {
37 : max = abs_value;
38 : }
39 : }
40 : }
41 :
42 252 : if (max == V8_INFINITY) {
43 54 : return *isolate->factory()->NewNumber(V8_INFINITY);
44 : }
45 :
46 225 : if (one_arg_is_nan) {
47 54 : return ReadOnlyRoots(isolate).nan_value();
48 : }
49 :
50 171 : if (max == 0) {
51 36 : return Smi::kZero;
52 : }
53 : DCHECK_GT(max, 0);
54 :
55 : // Kahan summation to avoid rounding errors.
56 : // Normalize the numbers to the largest one to avoid overflow.
57 : double sum = 0;
58 : double compensation = 0;
59 15327 : for (int i = 0; i < length; i++) {
60 15192 : double n = abs_values[i] / max;
61 7596 : double summand = n * n - compensation;
62 7596 : double preliminary = sum + summand;
63 7596 : compensation = (preliminary - sum) - summand;
64 : sum = preliminary;
65 : }
66 :
67 270 : return *isolate->factory()->NewNumber(std::sqrt(sum) * max);
68 : }
69 :
70 : } // namespace internal
71 122036 : } // namespace v8
|