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.
5 var rngstate; // Initialized to a Uint32Array during genesis.
17 %CheckIsBootstrapping();
19 var GlobalObject = global.Object;
20 var GlobalArray = global.Array;
22 //-------------------------------------------------------------------
24 // ECMA 262 - 15.8.2.1
31 // ECMA 262 - 15.8.2.2
32 function MathAcosJS(x) {
33 return %_MathAcos(+x);
36 // ECMA 262 - 15.8.2.3
37 function MathAsinJS(x) {
38 return %_MathAsin(+x);
41 // ECMA 262 - 15.8.2.4
42 function MathAtanJS(x) {
43 return %_MathAtan(+x);
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) {
52 return %_MathAtan2(y, x);
55 // ECMA 262 - 15.8.2.6
56 function MathCeil(x) {
57 return -%_MathFloor(-x);
60 // ECMA 262 - 15.8.2.8
62 return %MathExpRT(TO_NUMBER_INLINE(x));
65 // ECMA 262 - 15.8.2.9
66 function MathFloorJS(x) {
67 return %_MathFloor(+x);
70 // ECMA 262 - 15.8.2.10
72 return %_MathLogRT(TO_NUMBER_INLINE(x));
75 // ECMA 262 - 15.8.2.11
76 function MathMax(arg1, arg2) { // length == 2
77 var length = %_ArgumentsLength();
79 arg1 = TO_NUMBER_INLINE(arg1);
80 arg2 = TO_NUMBER_INLINE(arg2);
81 if (arg2 > arg1) return arg2;
82 if (arg1 > arg2) return arg1;
84 // Make sure -0 is considered less than +0.
85 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1;
87 // All comparisons failed, one of the arguments must be NaN.
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))) {
102 // ECMA 262 - 15.8.2.12
103 function MathMin(arg1, arg2) { // length == 2
104 var length = %_ArgumentsLength();
106 arg1 = TO_NUMBER_INLINE(arg1);
107 arg2 = TO_NUMBER_INLINE(arg2);
108 if (arg2 > arg1) return arg1;
109 if (arg1 > arg2) return arg2;
111 // Make sure -0 is considered less than +0.
112 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2;
114 // All comparisons failed, one of the arguments must be NaN.
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))) {
129 // ECMA 262 - 15.8.2.13
130 function MathPowJS(x, y) {
131 return %_MathPow(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
134 // ECMA 262 - 15.8.2.14
135 function MathRandom() {
136 var r0 = (MathImul(18030, rngstate[0] & 0xFFFF) + (rngstate[0] >>> 16)) | 0;
138 var r1 = (MathImul(36969, rngstate[1] & 0xFFFF) + (rngstate[1] >>> 16)) | 0;
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;
145 // ECMA 262 - 15.8.2.15
146 function MathRound(x) {
147 return %RoundNumber(TO_NUMBER_INLINE(x));
150 // ECMA 262 - 15.8.2.17
151 function MathSqrtJS(x) {
152 return %_MathSqrt(+x);
155 // Non-standard extension.
156 function MathImul(x, y) {
157 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y));
160 // ES6 draft 09-27-13, section 20.2.2.28.
161 function MathSign(x) {
164 if (x < 0) return -1;
169 // ES6 draft 09-27-13, section 20.2.2.34.
170 function MathTrunc(x) {
172 if (x > 0) return %_MathFloor(x);
173 if (x < 0) return -%_MathFloor(-x);
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);
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));
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));
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));
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);
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;
232 if (n > max) max = n;
236 // Kahan summation to avoid rounding errors.
237 // Normalize the numbers to the largest one to avoid overflow.
238 if (max === 0) max = 1;
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;
248 return %_MathSqrt(sum) * max;
251 // ES6 draft 09-27-13, section 20.2.2.16.
252 function MathFroundJS(x) {
253 return %MathFround(TO_NUMBER_INLINE(x));
256 // ES6 draft 07-18-14, section 20.2.2.11
257 function MathClz32JS(x) {
258 return %_MathClz32(x >>> 0);
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);
271 macro NEWTON_ITERATION_CBRT(x, approx)
272 (1.0 / 3.0) * (x / (approx * approx) + 2 * approx);
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);
284 // -------------------------------------------------------------------
286 // Instance class name can only be set on functions. That is the only
287 // purpose for MathConstructor.
288 function MathConstructor() {}
290 var Math = new MathConstructor();
292 %InternalSetPrototype(Math, GlobalObject.prototype);
293 %AddNamedProperty(global, "Math", Math, DONT_ENUM);
294 %FunctionSetInstanceClassName(MathConstructor, 'Math');
296 %AddNamedProperty(Math, symbolToStringTag, "Math", READ_ONLY | DONT_ENUM);
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
314 // Set up non-enumerable functions of the Math object and
316 InstallFunctions(Math, DONT_ENUM, GlobalArray(
317 "random", MathRandom,
324 "floor", MathFloorJS,
328 "atan2", MathAtan2JS,
340 "fround", MathFroundJS,
341 "clz32", MathClz32JS,
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);
358 // Expose to the global scope.
361 $floor = MathFloorJS;