deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / math.js
1 // Copyright 2012 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 var rngstate;  // Initialized to a Uint32Array during genesis.
6
7 var $abs;
8 var $exp;
9 var $floor;
10 var $max;
11 var $min;
12
13 (function() {
14
15 "use strict";
16
17 %CheckIsBootstrapping();
18
19 var GlobalObject = global.Object;
20 var GlobalArray = global.Array;
21
22 //-------------------------------------------------------------------
23
24 // ECMA 262 - 15.8.2.1
25 function MathAbs(x) {
26   x = +x;
27   if (x > 0) return x;
28   return 0 - x;
29 }
30
31 // ECMA 262 - 15.8.2.2
32 function MathAcosJS(x) {
33   return %_MathAcos(+x);
34 }
35
36 // ECMA 262 - 15.8.2.3
37 function MathAsinJS(x) {
38   return %_MathAsin(+x);
39 }
40
41 // ECMA 262 - 15.8.2.4
42 function MathAtanJS(x) {
43   return %_MathAtan(+x);
44 }
45
46 // ECMA 262 - 15.8.2.5
47 // The naming of y and x matches the spec, as does the order in which
48 // ToNumber (valueOf) is called.
49 function MathAtan2JS(y, x) {
50   y = +y;
51   x = +x;
52   return %_MathAtan2(y, x);
53 }
54
55 // ECMA 262 - 15.8.2.6
56 function MathCeil(x) {
57   return -%_MathFloor(-x);
58 }
59
60 // ECMA 262 - 15.8.2.8
61 function MathExp(x) {
62   return %MathExpRT(TO_NUMBER_INLINE(x));
63 }
64
65 // ECMA 262 - 15.8.2.9
66 function MathFloorJS(x) {
67   return %_MathFloor(+x);
68 }
69
70 // ECMA 262 - 15.8.2.10
71 function MathLog(x) {
72   return %_MathLogRT(TO_NUMBER_INLINE(x));
73 }
74
75 // ECMA 262 - 15.8.2.11
76 function MathMax(arg1, arg2) {  // length == 2
77   var length = %_ArgumentsLength();
78   if (length == 2) {
79     arg1 = TO_NUMBER_INLINE(arg1);
80     arg2 = TO_NUMBER_INLINE(arg2);
81     if (arg2 > arg1) return arg2;
82     if (arg1 > arg2) return arg1;
83     if (arg1 == arg2) {
84       // Make sure -0 is considered less than +0.
85       return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1;
86     }
87     // All comparisons failed, one of the arguments must be NaN.
88     return NAN;
89   }
90   var r = -INFINITY;
91   for (var i = 0; i < length; i++) {
92     var n = %_Arguments(i);
93     if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
94     // Make sure +0 is considered greater than -0.
95     if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) {
96       r = n;
97     }
98   }
99   return r;
100 }
101
102 // ECMA 262 - 15.8.2.12
103 function MathMin(arg1, arg2) {  // length == 2
104   var length = %_ArgumentsLength();
105   if (length == 2) {
106     arg1 = TO_NUMBER_INLINE(arg1);
107     arg2 = TO_NUMBER_INLINE(arg2);
108     if (arg2 > arg1) return arg1;
109     if (arg1 > arg2) return arg2;
110     if (arg1 == arg2) {
111       // Make sure -0 is considered less than +0.
112       return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2;
113     }
114     // All comparisons failed, one of the arguments must be NaN.
115     return NAN;
116   }
117   var r = INFINITY;
118   for (var i = 0; i < length; i++) {
119     var n = %_Arguments(i);
120     if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
121     // Make sure -0 is considered less than +0.
122     if (NUMBER_IS_NAN(n) || n < r || (r === 0 && n === 0 && %_IsMinusZero(n))) {
123       r = n;
124     }
125   }
126   return r;
127 }
128
129 // ECMA 262 - 15.8.2.13
130 function MathPowJS(x, y) {
131   return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
132 }
133
134 // ECMA 262 - 15.8.2.14
135 function MathRandom() {
136   var r0 = (MathImul(18030, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
137   rngstate[0] = r0;
138   var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0;
139   rngstate[1] = r1;
140   var x = ((r0 << 16) + (r1 & 0xFFFF)) | 0;
141   // Division by 0x100000000 through multiplication by reciprocal.
142   return (x < 0 ? (x + 0x100000000) : x) * 2.3283064365386962890625e-10;
143 }
144
145 // ECMA 262 - 15.8.2.15
146 function MathRound(x) {
147   return %RoundNumber(TO_NUMBER_INLINE(x));
148 }
149
150 // ECMA 262 - 15.8.2.17
151 function MathSqrtJS(x) {
152   return %_MathSqrt(+x);
153 }
154
155 // Non-standard extension.
156 function MathImul(x, y) {
157   return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
158 }
159
160 // ES6 draft 09-27-13, section 20.2.2.28.
161 function MathSign(x) {
162   x = +x;
163   if (x > 0) return 1;
164   if (x < 0) return -1;
165   // -0, 0 or NaN.
166   return x;
167 }
168
169 // ES6 draft 09-27-13, section 20.2.2.34.
170 function MathTrunc(x) {
171   x = +x;
172   if (x > 0) return %_MathFloor(x);
173   if (x < 0) return -%_MathFloor(-x);
174   // -0, 0 or NaN.
175   return x;
176 }
177
178 // ES6 draft 09-27-13, section 20.2.2.33.
179 function MathTanh(x) {
180   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
181   // Idempotent for +/-0.
182   if (x === 0) return x;
183   // Returns +/-1 for +/-Infinity.
184   if (!NUMBER_IS_FINITE(x)) return MathSign(x);
185   var exp1 = MathExp(x);
186   var exp2 = MathExp(-x);
187   return (exp1 - exp2) / (exp1 + exp2);
188 }
189
190 // ES6 draft 09-27-13, section 20.2.2.5.
191 function MathAsinh(x) {
192   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
193   // Idempotent for NaN, +/-0 and +/-Infinity.
194   if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
195   if (x > 0) return MathLog(x + %_MathSqrt(x * x + 1));
196   // This is to prevent numerical errors caused by large negative x.
197   return -MathLog(-x + %_MathSqrt(x * x + 1));
198 }
199
200 // ES6 draft 09-27-13, section 20.2.2.3.
201 function MathAcosh(x) {
202   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
203   if (x < 1) return NAN;
204   // Idempotent for NaN and +Infinity.
205   if (!NUMBER_IS_FINITE(x)) return x;
206   return MathLog(x + %_MathSqrt(x + 1) * %_MathSqrt(x - 1));
207 }
208
209 // ES6 draft 09-27-13, section 20.2.2.7.
210 function MathAtanh(x) {
211   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
212   // Idempotent for +/-0.
213   if (x === 0) return x;
214   // Returns NaN for NaN and +/- Infinity.
215   if (!NUMBER_IS_FINITE(x)) return NAN;
216   return 0.5 * MathLog((1 + x) / (1 - x));
217 }
218
219 // ES6 draft 09-27-13, section 20.2.2.17.
220 function MathHypot(x, y) {  // Function length is 2.
221   // We may want to introduce fast paths for two arguments and when
222   // normalization to avoid overflow is not necessary.  For now, we
223   // simply assume the general case.
224   var length = %_ArgumentsLength();
225   var args = new InternalArray(length);
226   var max = 0;
227   for (var i = 0; i < length; i++) {
228     var n = %_Arguments(i);
229     if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
230     if (n === INFINITY || n === -INFINITY) return INFINITY;
231     n = MathAbs(n);
232     if (n > max) max = n;
233     args[i] = n;
234   }
235
236   // Kahan summation to avoid rounding errors.
237   // Normalize the numbers to the largest one to avoid overflow.
238   if (max === 0) max = 1;
239   var sum = 0;
240   var compensation = 0;
241   for (var i = 0; i < length; i++) {
242     var n = args[i] / max;
243     var summand = n * n - compensation;
244     var preliminary = sum + summand;
245     compensation = (preliminary - sum) - summand;
246     sum = preliminary;
247   }
248   return %_MathSqrt(sum) * max;
249 }
250
251 // ES6 draft 09-27-13, section 20.2.2.16.
252 function MathFroundJS(x) {
253   return %MathFround(TO_NUMBER_INLINE(x));
254 }
255
256 // ES6 draft 07-18-14, section 20.2.2.11
257 function MathClz32JS(x) {
258   return %_MathClz32(x >>> 0);
259 }
260
261 // ES6 draft 09-27-13, section 20.2.2.9.
262 // Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm
263 // Using initial approximation adapted from Kahan's cbrt and 4 iterations
264 // of Newton's method.
265 function MathCbrt(x) {
266   if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
267   if (x == 0 || !NUMBER_IS_FINITE(x)) return x;
268   return x >= 0 ? CubeRoot(x) : -CubeRoot(-x);
269 }
270
271 macro NEWTON_ITERATION_CBRT(x, approx)
272   (1.0 / 3.0) * (x / (approx * approx) + 2 * approx);
273 endmacro
274
275 function CubeRoot(x) {
276   var approx_hi = MathFloorJS(%_DoubleHi(x) / 3) + 0x2A9F7893;
277   var approx = %_ConstructDouble(approx_hi, 0);
278   approx = NEWTON_ITERATION_CBRT(x, approx);
279   approx = NEWTON_ITERATION_CBRT(x, approx);
280   approx = NEWTON_ITERATION_CBRT(x, approx);
281   return NEWTON_ITERATION_CBRT(x, approx);
282 }
283
284 // -------------------------------------------------------------------
285
286 // Instance class name can only be set on functions. That is the only
287 // purpose for MathConstructor.
288 function MathConstructor() {}
289
290 var Math = new MathConstructor();
291
292 %InternalSetPrototype(Math, GlobalObject.prototype);
293 %AddNamedProperty(global, "Math", Math, DONT_ENUM);
294 %FunctionSetInstanceClassName(MathConstructor, 'Math');
295
296 %AddNamedProperty(Math, symbolToStringTag, "Math", READ_ONLY | DONT_ENUM);
297
298 // Set up math constants.
299 InstallConstants(Math, GlobalArray(
300   // ECMA-262, section 15.8.1.1.
301   "E", 2.7182818284590452354,
302   // ECMA-262, section 15.8.1.2.
303   "LN10", 2.302585092994046,
304   // ECMA-262, section 15.8.1.3.
305   "LN2", 0.6931471805599453,
306   // ECMA-262, section 15.8.1.4.
307   "LOG2E", 1.4426950408889634,
308   "LOG10E", 0.4342944819032518,
309   "PI", 3.1415926535897932,
310   "SQRT1_2", 0.7071067811865476,
311   "SQRT2", 1.4142135623730951
312 ));
313
314 // Set up non-enumerable functions of the Math object and
315 // set their names.
316 InstallFunctions(Math, DONT_ENUM, GlobalArray(
317   "random", MathRandom,
318   "abs", MathAbs,
319   "acos", MathAcosJS,
320   "asin", MathAsinJS,
321   "atan", MathAtanJS,
322   "ceil", MathCeil,
323   "exp", MathExp,
324   "floor", MathFloorJS,
325   "log", MathLog,
326   "round", MathRound,
327   "sqrt", MathSqrtJS,
328   "atan2", MathAtan2JS,
329   "pow", MathPowJS,
330   "max", MathMax,
331   "min", MathMin,
332   "imul", MathImul,
333   "sign", MathSign,
334   "trunc", MathTrunc,
335   "tanh", MathTanh,
336   "asinh", MathAsinh,
337   "acosh", MathAcosh,
338   "atanh", MathAtanh,
339   "hypot", MathHypot,
340   "fround", MathFroundJS,
341   "clz32", MathClz32JS,
342   "cbrt", MathCbrt
343 ));
344
345 %SetInlineBuiltinFlag(MathAbs);
346 %SetInlineBuiltinFlag(MathAcosJS);
347 %SetInlineBuiltinFlag(MathAsinJS);
348 %SetInlineBuiltinFlag(MathAtanJS);
349 %SetInlineBuiltinFlag(MathAtan2JS);
350 %SetInlineBuiltinFlag(MathCeil);
351 %SetInlineBuiltinFlag(MathClz32JS);
352 %SetInlineBuiltinFlag(MathFloorJS);
353 %SetInlineBuiltinFlag(MathRandom);
354 %SetInlineBuiltinFlag(MathSign);
355 %SetInlineBuiltinFlag(MathSqrtJS);
356 %SetInlineBuiltinFlag(MathTrunc);
357
358 // Expose to the global scope.
359 $abs = MathAbs;
360 $exp = MathExp;
361 $floor = MathFloorJS;
362 $max = MathMax;
363 $min = MathMin;
364
365 })();