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 1221 : BUILTIN(MathHypot) {
18 : HandleScope scope(isolate);
19 407 : int const length = args.length() - 1;
20 407 : if (length == 0) return Smi::kZero;
21 : DCHECK_LT(0, length);
22 : double max = 0;
23 : bool one_arg_is_nan = false;
24 : List<double> abs_values(length);
25 12968 : for (int i = 0; i < length; i++) {
26 12182 : Handle<Object> x = args.at(i + 1);
27 24364 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x));
28 : double abs_value = std::abs(x->Number());
29 :
30 12182 : if (std::isnan(abs_value)) {
31 : one_arg_is_nan = true;
32 : } else {
33 12070 : abs_values.Add(abs_value);
34 12070 : if (max < abs_value) {
35 : max = abs_value;
36 : }
37 : }
38 : }
39 :
40 393 : if (max == V8_INFINITY) {
41 86 : return *isolate->factory()->NewNumber(V8_INFINITY);
42 : }
43 :
44 350 : if (one_arg_is_nan) {
45 84 : return isolate->heap()->nan_value();
46 : }
47 :
48 266 : if (max == 0) {
49 : return Smi::kZero;
50 : }
51 : DCHECK_GT(max, 0);
52 :
53 : // Kahan summation to avoid rounding errors.
54 : // Normalize the numbers to the largest one to avoid overflow.
55 : double sum = 0;
56 : double compensation = 0;
57 11816 : for (int i = 0; i < length; i++) {
58 11816 : double n = abs_values.at(i) / max;
59 11816 : double summand = n * n - compensation;
60 11816 : double preliminary = sum + summand;
61 11816 : compensation = (preliminary - sum) - summand;
62 : sum = preliminary;
63 : }
64 :
65 420 : return *isolate->factory()->NewNumber(std::sqrt(sum) * max);
66 : }
67 :
68 : } // namespace internal
69 : } // namespace v8
|