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 786 : BUILTIN(MathHypot) {
18 : HandleScope scope(isolate);
19 262 : int const length = args.length() - 1;
20 262 : 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 253 : abs_values.reserve(length);
26 8338 : for (int i = 0; i < length; i++) {
27 7832 : Handle<Object> x = args.at(i + 1);
28 15664 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x));
29 7832 : double abs_value = std::abs(x->Number());
30 :
31 7832 : if (std::isnan(abs_value)) {
32 : one_arg_is_nan = true;
33 : } else {
34 7760 : abs_values.push_back(abs_value);
35 7760 : if (max < abs_value) {
36 : max = abs_value;
37 : }
38 : }
39 : }
40 :
41 253 : if (max == V8_INFINITY) {
42 56 : return *isolate->factory()->NewNumber(V8_INFINITY);
43 : }
44 :
45 225 : if (one_arg_is_nan) {
46 54 : return isolate->heap()->nan_value();
47 : }
48 :
49 171 : if (max == 0) {
50 : return Smi::kZero;
51 : }
52 : DCHECK_GT(max, 0);
53 :
54 : // Kahan summation to avoid rounding errors.
55 : // Normalize the numbers to the largest one to avoid overflow.
56 : double sum = 0;
57 : double compensation = 0;
58 7596 : for (int i = 0; i < length; i++) {
59 15192 : double n = abs_values[i] / max;
60 7596 : double summand = n * n - compensation;
61 7596 : double preliminary = sum + summand;
62 7596 : compensation = (preliminary - sum) - summand;
63 : sum = preliminary;
64 : }
65 :
66 270 : return *isolate->factory()->NewNumber(std::sqrt(sum) * max);
67 : }
68 :
69 : } // namespace internal
70 : } // namespace v8
|