blob: a698fd4285cac1adbc1396f84deab9ab6d29e97c [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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078// ECMA 262 - 15.8.2.13
79function MathPowJS(x, y) {
80 return %_MathPow(TO_NUMBER(x), TO_NUMBER(y));
81}
82
83// ECMA 262 - 15.8.2.14
84function MathRandom() {
85 if (nextRandomIndex >= kRandomBatchSize) {
86 randomNumbers = %GenerateRandomNumbers(randomNumbers);
87 nextRandomIndex = kRandomNumberStart;
88 }
89 return randomNumbers[nextRandomIndex++];
90}
91
92function MathRandomRaw() {
93 if (nextRandomIndex >= kRandomBatchSize) {
94 randomNumbers = %GenerateRandomNumbers(randomNumbers);
95 nextRandomIndex = kRandomNumberStart;
96 }
97 return %_DoubleLo(randomNumbers[nextRandomIndex++]) & 0x3FFFFFFF;
98}
99
100// ECMA 262 - 15.8.2.15
101function MathRound(x) {
102 return %RoundNumber(TO_NUMBER(x));
103}
104
105// ECMA 262 - 15.8.2.17
106function MathSqrtJS(x) {
107 return %_MathSqrt(+x);
108}
109
110// Non-standard extension.
111function MathImul(x, y) {
112 return %NumberImul(TO_NUMBER(x), TO_NUMBER(y));
113}
114
115// ES6 draft 09-27-13, section 20.2.2.28.
116function MathSign(x) {
117 x = +x;
118 if (x > 0) return 1;
119 if (x < 0) return -1;
120 // -0, 0 or NaN.
121 return x;
122}
123
124// ES6 draft 09-27-13, section 20.2.2.34.
125function MathTrunc(x) {
126 x = +x;
127 if (x > 0) return %_MathFloor(x);
128 if (x < 0) return -%_MathFloor(-x);
129 // -0, 0 or NaN.
130 return x;
131}
132
133// ES6 draft 09-27-13, section 20.2.2.5.
134function MathAsinh(x) {
135 x = TO_NUMBER(x);
136 // Idempotent for NaN, +/-0 and +/-Infinity.
137 if (x === 0 || !NUMBER_IS_FINITE(x)) return x;
138 if (x > 0) return MathLog(x + %_MathSqrt(x * x + 1));
139 // This is to prevent numerical errors caused by large negative x.
140 return -MathLog(-x + %_MathSqrt(x * x + 1));
141}
142
143// ES6 draft 09-27-13, section 20.2.2.3.
144function MathAcosh(x) {
145 x = TO_NUMBER(x);
146 if (x < 1) return NaN;
147 // Idempotent for NaN and +Infinity.
148 if (!NUMBER_IS_FINITE(x)) return x;
149 return MathLog(x + %_MathSqrt(x + 1) * %_MathSqrt(x - 1));
150}
151
152// ES6 draft 09-27-13, section 20.2.2.7.
153function MathAtanh(x) {
154 x = TO_NUMBER(x);
155 // Idempotent for +/-0.
156 if (x === 0) return x;
157 // Returns NaN for NaN and +/- Infinity.
158 if (!NUMBER_IS_FINITE(x)) return NaN;
159 return 0.5 * MathLog((1 + x) / (1 - x));
160}
161
162// ES6 draft 09-27-13, section 20.2.2.17.
163function MathHypot(x, y) { // Function length is 2.
164 // We may want to introduce fast paths for two arguments and when
165 // normalization to avoid overflow is not necessary. For now, we
166 // simply assume the general case.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100167 var length = arguments.length;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 var max = 0;
169 for (var i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100170 var n = MathAbs(arguments[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 if (n > max) max = n;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100172 arguments[i] = n;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000173 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100174 if (max === INFINITY) return INFINITY;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000175
176 // Kahan summation to avoid rounding errors.
177 // Normalize the numbers to the largest one to avoid overflow.
178 if (max === 0) max = 1;
179 var sum = 0;
180 var compensation = 0;
181 for (var i = 0; i < length; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100182 var n = arguments[i] / max;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 var summand = n * n - compensation;
184 var preliminary = sum + summand;
185 compensation = (preliminary - sum) - summand;
186 sum = preliminary;
187 }
188 return %_MathSqrt(sum) * max;
189}
190
191// ES6 draft 09-27-13, section 20.2.2.16.
192function MathFroundJS(x) {
193 return %MathFround(TO_NUMBER(x));
194}
195
196// ES6 draft 07-18-14, section 20.2.2.11
197function MathClz32JS(x) {
198 return %_MathClz32(x >>> 0);
199}
200
201// ES6 draft 09-27-13, section 20.2.2.9.
202// Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm
203// Using initial approximation adapted from Kahan's cbrt and 4 iterations
204// of Newton's method.
205function MathCbrt(x) {
206 x = TO_NUMBER(x);
207 if (x == 0 || !NUMBER_IS_FINITE(x)) return x;
208 return x >= 0 ? CubeRoot(x) : -CubeRoot(-x);
209}
210
211macro NEWTON_ITERATION_CBRT(x, approx)
212 (1.0 / 3.0) * (x / (approx * approx) + 2 * approx);
213endmacro
214
215function CubeRoot(x) {
216 var approx_hi = MathFloorJS(%_DoubleHi(x) / 3) + 0x2A9F7893;
217 var approx = %_ConstructDouble(approx_hi | 0, 0);
218 approx = NEWTON_ITERATION_CBRT(x, approx);
219 approx = NEWTON_ITERATION_CBRT(x, approx);
220 approx = NEWTON_ITERATION_CBRT(x, approx);
221 return NEWTON_ITERATION_CBRT(x, approx);
222}
223
224// -------------------------------------------------------------------
225
226%AddNamedProperty(GlobalMath, toStringTagSymbol, "Math", READ_ONLY | DONT_ENUM);
227
228// Set up math constants.
229utils.InstallConstants(GlobalMath, [
230 // ECMA-262, section 15.8.1.1.
231 "E", 2.7182818284590452354,
232 // ECMA-262, section 15.8.1.2.
233 "LN10", 2.302585092994046,
234 // ECMA-262, section 15.8.1.3.
235 "LN2", 0.6931471805599453,
236 // ECMA-262, section 15.8.1.4.
237 "LOG2E", 1.4426950408889634,
238 "LOG10E", 0.4342944819032518,
239 "PI", 3.1415926535897932,
240 "SQRT1_2", 0.7071067811865476,
241 "SQRT2", 1.4142135623730951
242]);
243
244// Set up non-enumerable functions of the Math object and
245// set their names.
246utils.InstallFunctions(GlobalMath, DONT_ENUM, [
247 "random", MathRandom,
248 "abs", MathAbs,
249 "acos", MathAcosJS,
250 "asin", MathAsinJS,
251 "atan", MathAtanJS,
252 "ceil", MathCeil,
253 "exp", MathExp,
254 "floor", MathFloorJS,
255 "log", MathLog,
256 "round", MathRound,
257 "sqrt", MathSqrtJS,
258 "atan2", MathAtan2JS,
259 "pow", MathPowJS,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 "imul", MathImul,
261 "sign", MathSign,
262 "trunc", MathTrunc,
263 "asinh", MathAsinh,
264 "acosh", MathAcosh,
265 "atanh", MathAtanh,
266 "hypot", MathHypot,
267 "fround", MathFroundJS,
268 "clz32", MathClz32JS,
269 "cbrt", MathCbrt
270]);
271
272%SetForceInlineFlag(MathAbs);
273%SetForceInlineFlag(MathAcosJS);
274%SetForceInlineFlag(MathAsinJS);
275%SetForceInlineFlag(MathAtanJS);
276%SetForceInlineFlag(MathAtan2JS);
277%SetForceInlineFlag(MathCeil);
278%SetForceInlineFlag(MathClz32JS);
279%SetForceInlineFlag(MathFloorJS);
280%SetForceInlineFlag(MathRandom);
281%SetForceInlineFlag(MathSign);
282%SetForceInlineFlag(MathSqrtJS);
283%SetForceInlineFlag(MathTrunc);
284
285// -------------------------------------------------------------------
286// Exports
287
288utils.Export(function(to) {
289 to.MathAbs = MathAbs;
290 to.MathExp = MathExp;
291 to.MathFloor = MathFloorJS;
292 to.IntRandom = MathRandomRaw;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293});
294
295})