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