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