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