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.
7 // This file relies on the fact that the following declarations have been made
9 // var $Object = global.Object;
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;
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();
22 // -------------------------------------------------------------------
24 // ECMA 262 - 15.8.2.1
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;
32 // ECMA 262 - 15.8.2.2
33 function MathAcosJS(x) {
34 return %MathAcos(TO_NUMBER_INLINE(x));
37 // ECMA 262 - 15.8.2.3
38 function MathAsinJS(x) {
39 return %MathAsin(TO_NUMBER_INLINE(x));
42 // ECMA 262 - 15.8.2.4
43 function MathAtanJS(x) {
44 return %MathAtan(TO_NUMBER_INLINE(x));
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));
54 // ECMA 262 - 15.8.2.6
55 function MathCeil(x) {
56 return -MathFloor(-x);
59 // ECMA 262 - 15.8.2.8
61 return %MathExpRT(TO_NUMBER_INLINE(x));
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.
76 return %MathFloorRT(x);
80 // ECMA 262 - 15.8.2.10
82 return %_MathLogRT(TO_NUMBER_INLINE(x));
85 // ECMA 262 - 15.8.2.11
86 function MathMax(arg1, arg2) { // length == 2
87 var length = %_ArgumentsLength();
89 arg1 = TO_NUMBER_INLINE(arg1);
90 arg2 = TO_NUMBER_INLINE(arg2);
91 if (arg2 > arg1) return arg2;
92 if (arg1 > arg2) return arg1;
94 // Make sure -0 is considered less than +0.
95 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1;
97 // All comparisons failed, one of the arguments must be NaN.
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))) {
112 // ECMA 262 - 15.8.2.12
113 function MathMin(arg1, arg2) { // length == 2
114 var length = %_ArgumentsLength();
116 arg1 = TO_NUMBER_INLINE(arg1);
117 arg2 = TO_NUMBER_INLINE(arg2);
118 if (arg2 > arg1) return arg1;
119 if (arg1 > arg2) return arg2;
121 // Make sure -0 is considered less than +0.
122 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2;
124 // All comparisons failed, one of the arguments must be NaN.
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))) {
139 // ECMA 262 - 15.8.2.13
140 function MathPow(x, y) {
141 return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
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;
149 var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0;
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;
156 // ECMA 262 - 15.8.2.15
157 function MathRound(x) {
158 return %RoundNumber(TO_NUMBER_INLINE(x));
161 // ECMA 262 - 15.8.2.17
162 function MathSqrt(x) {
163 return %_MathSqrtRT(TO_NUMBER_INLINE(x));
166 // Non-standard extension.
167 function MathImul(x, y) {
168 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
171 // ES6 draft 09-27-13, section 20.2.2.28.
172 function MathSign(x) {
173 x = TO_NUMBER_INLINE(x);
175 if (x < 0) return -1;
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);
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);
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));
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));
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));
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).
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).
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);
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;
254 if (n > max) max = n;
258 // Kahan summation to avoid rounding errors.
259 // Normalize the numbers to the largest one to avoid overflow.
260 if (max === 0) max = 1;
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;
270 return MathSqrt(sum) * max;
273 // ES6 draft 09-27-13, section 20.2.2.16.
274 function MathFroundJS(x) {
275 return %MathFround(TO_NUMBER_INLINE(x));
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;
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; };
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);
302 macro NEWTON_ITERATION_CBRT(x, approx)
303 (1.0 / 3.0) * (x / (approx * approx) + 2 * approx);
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);
315 // -------------------------------------------------------------------
317 function SetUpMath() {
318 %CheckIsBootstrapping();
320 %InternalSetPrototype($Math, $Object.prototype);
321 %AddNamedProperty(global, "Math", $Math, DONT_ENUM);
322 %FunctionSetInstanceClassName(MathConstructor, 'Math');
324 %AddNamedProperty($Math, symbolToStringTag, "Math", READ_ONLY | DONT_ENUM);
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
342 // Set up non-enumerable functions of the Math object and
344 InstallFunctions($Math, DONT_ENUM, $Array(
345 "random", MathRandom,
351 "cos", MathCos, // implemented by third_party/fdlibm
356 "sin", MathSin, // implemented by third_party/fdlibm
358 "tan", MathTan, // implemented by third_party/fdlibm
359 "atan2", MathAtan2JS,
366 "sinh", MathSinh, // implemented by third_party/fdlibm
367 "cosh", MathCosh, // implemented by third_party/fdlibm
375 "fround", MathFroundJS,
378 "log1p", MathLog1p, // implemented by third_party/fdlibm
379 "expm1", MathExpm1 // implemented by third_party/fdlibm
382 %SetInlineBuiltinFlag(MathCeil);
383 %SetInlineBuiltinFlag(MathRandom);
384 %SetInlineBuiltinFlag(MathSin);
385 %SetInlineBuiltinFlag(MathCos);