OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 'use strict'; | |
6 | |
7 // ES6 draft 09-27-13, section 20.2.2.28. | |
8 function MathSign(x) { | |
9 x = TO_NUMBER_INLINE(x); | |
10 if (x > 0) return 1; | |
11 if (x < 0) return -1; | |
12 if (x === 0) return x; | |
13 return NAN; | |
14 } | |
15 | |
16 | |
17 // ES6 draft 09-27-13, section 20.2.2.34. | |
18 function MathTrunc(x) { | |
19 x = TO_NUMBER_INLINE(x); | |
20 if (x > 0) return MathFloor(x); | |
21 if (x < 0) return MathCeil(x); | |
22 if (x === 0) return x; | |
23 return NAN; | |
24 } | |
25 | |
26 | |
27 // ES6 draft 09-27-13, section 20.2.2.30. | |
28 function MathSinh(x) { | |
29 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
30 // Idempotent for NaN, +/-0 and +/-Infinity. | |
31 if (x === 0 || !NUMBER_IS_FINITE(x)) return x; | |
32 return (MathExp(x) - MathExp(-x)) / 2; | |
33 } | |
34 | |
35 | |
36 // ES6 draft 09-27-13, section 20.2.2.12. | |
37 function MathCosh(x) { | |
38 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
39 if (!NUMBER_IS_FINITE(x)) return MathAbs(x); | |
40 return (MathExp(x) + MathExp(-x)) / 2; | |
41 } | |
42 | |
43 | |
44 // ES6 draft 09-27-13, section 20.2.2.33. | |
45 function MathTanh(x) { | |
46 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
47 // Idempotent for +/-0. | |
48 if (x === 0) return x; | |
49 // Returns +/-1 for +/-Infinity. | |
50 if (!NUMBER_IS_FINITE(x)) return MathSign(x); | |
51 var exp1 = MathExp(x); | |
52 var exp2 = MathExp(-x); | |
53 return (exp1 - exp2) / (exp1 + exp2); | |
54 } | |
55 | |
56 | |
57 // ES6 draft 09-27-13, section 20.2.2.5. | |
58 function MathAsinh(x) { | |
59 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
60 // Idempotent for NaN, +/-0 and +/-Infinity. | |
61 if (x === 0 || !NUMBER_IS_FINITE(x)) return x; | |
62 if (x > 0) return MathLog(x + MathSqrt(x * x + 1)); | |
63 // This is to prevent numerical errors caused by large negative x. | |
64 return -MathLog(-x + MathSqrt(x * x + 1)); | |
65 } | |
66 | |
67 | |
68 // ES6 draft 09-27-13, section 20.2.2.3. | |
69 function MathAcosh(x) { | |
70 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
71 if (x < 1) return NAN; | |
72 // Idempotent for NaN and +Infinity. | |
73 if (!NUMBER_IS_FINITE(x)) return x; | |
74 return MathLog(x + MathSqrt(x + 1) * MathSqrt(x - 1)); | |
75 } | |
76 | |
77 | |
78 // ES6 draft 09-27-13, section 20.2.2.7. | |
79 function MathAtanh(x) { | |
80 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
81 // Idempotent for +/-0. | |
82 if (x === 0) return x; | |
83 // Returns NaN for NaN and +/- Infinity. | |
84 if (!NUMBER_IS_FINITE(x)) return NAN; | |
85 return 0.5 * MathLog((1 + x) / (1 - x)); | |
86 } | |
87 | |
88 | |
89 // ES6 draft 09-27-13, section 20.2.2.21. | |
90 function MathLog10(x) { | |
91 return MathLog(x) * 0.434294481903251828; // log10(x) = log(x)/log(10). | |
92 } | |
93 | |
94 | |
95 // ES6 draft 09-27-13, section 20.2.2.22. | |
96 function MathLog2(x) { | |
97 return MathLog(x) * 1.442695040888963407; // log2(x) = log(x)/log(2). | |
98 } | |
99 | |
100 | |
101 // ES6 draft 09-27-13, section 20.2.2.17. | |
102 function MathHypot(x, y) { // Function length is 2. | |
103 // We may want to introduce fast paths for two arguments and when | |
104 // normalization to avoid overflow is not necessary. For now, we | |
105 // simply assume the general case. | |
106 var length = %_ArgumentsLength(); | |
107 var args = new InternalArray(length); | |
108 var max = 0; | |
109 for (var i = 0; i < length; i++) { | |
110 var n = %_Arguments(i); | |
111 if (!IS_NUMBER(n)) n = NonNumberToNumber(n); | |
112 if (n === INFINITY || n === -INFINITY) return INFINITY; | |
113 n = MathAbs(n); | |
114 if (n > max) max = n; | |
115 args[i] = n; | |
116 } | |
117 | |
118 // Kahan summation to avoid rounding errors. | |
119 // Normalize the numbers to the largest one to avoid overflow. | |
120 if (max === 0) max = 1; | |
121 var sum = 0; | |
122 var compensation = 0; | |
123 for (var i = 0; i < length; i++) { | |
124 var n = args[i] / max; | |
125 var summand = n * n - compensation; | |
126 var preliminary = sum + summand; | |
127 compensation = (preliminary - sum) - summand; | |
128 sum = preliminary; | |
129 } | |
130 return MathSqrt(sum) * max; | |
131 } | |
132 | |
133 | |
134 // ES6 draft 09-27-13, section 20.2.2.16. | |
135 function MathFroundJS(x) { | |
136 return %MathFround(TO_NUMBER_INLINE(x)); | |
137 } | |
138 | |
139 | |
140 function MathClz32(x) { | |
141 x = ToUint32(TO_NUMBER_INLINE(x)); | |
142 if (x == 0) return 32; | |
143 var result = 0; | |
144 // Binary search. | |
145 if ((x & 0xFFFF0000) === 0) { x <<= 16; result += 16; }; | |
146 if ((x & 0xFF000000) === 0) { x <<= 8; result += 8; }; | |
147 if ((x & 0xF0000000) === 0) { x <<= 4; result += 4; }; | |
148 if ((x & 0xC0000000) === 0) { x <<= 2; result += 2; }; | |
149 if ((x & 0x80000000) === 0) { x <<= 1; result += 1; }; | |
150 return result; | |
151 } | |
152 | |
153 | |
154 // ES6 draft 09-27-13, section 20.2.2.9. | |
155 // Cube root approximation, refer to: http://metamerist.com/cbrt/cbrt.htm | |
156 // Using initial approximation adapted from Kahan's cbrt and 4 iterations | |
157 // of Newton's method. | |
158 function MathCbrt(x) { | |
159 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
160 if (x == 0 || !NUMBER_IS_FINITE(x)) return x; | |
161 return x >= 0 ? CubeRoot(x) : -CubeRoot(-x); | |
162 } | |
163 | |
164 macro NEWTON_ITERATION_CBRT(x, approx) | |
165 (1.0 / 3.0) * (x / (approx * approx) + 2 * approx); | |
166 endmacro | |
167 | |
168 function CubeRoot(x) { | |
169 var approx_hi = MathFloor(%_DoubleHi(x) / 3) + 0x2A9F7893; | |
170 var approx = %_ConstructDouble(approx_hi, 0); | |
171 approx = NEWTON_ITERATION_CBRT(x, approx); | |
172 approx = NEWTON_ITERATION_CBRT(x, approx); | |
173 approx = NEWTON_ITERATION_CBRT(x, approx); | |
174 return NEWTON_ITERATION_CBRT(x, approx); | |
175 } | |
176 | |
177 | |
178 | |
179 // ES6 draft 09-27-13, section 20.2.2.14. | |
180 // Use Taylor series to approximate. | |
181 // exp(x) - 1 at 0 == -1 + exp(0) + exp'(0)*x/1! + exp''(0)*x^2/2! + ... | |
182 // == x/1! + x^2/2! + x^3/3! + ... | |
183 // The closer x is to 0, the fewer terms are required. | |
184 function MathExpm1(x) { | |
185 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
186 var xabs = MathAbs(x); | |
187 if (xabs < 2E-7) { | |
188 return x * (1 + x * (1/2)); | |
189 } else if (xabs < 6E-5) { | |
190 return x * (1 + x * (1/2 + x * (1/6))); | |
191 } else if (xabs < 2E-2) { | |
192 return x * (1 + x * (1/2 + x * (1/6 + | |
193 x * (1/24 + x * (1/120 + x * (1/720)))))); | |
194 } else { // Use regular exp if not close enough to 0. | |
195 return MathExp(x) - 1; | |
196 } | |
197 } | |
198 | |
199 | |
200 // ES6 draft 09-27-13, section 20.2.2.20. | |
201 // Use Taylor series to approximate. With y = x + 1; | |
202 // log(y) at 1 == log(1) + log'(1)(y-1)/1! + log''(1)(y-1)^2/2! + ... | |
203 // == 0 + x - x^2/2 + x^3/3 ... | |
204 // The closer x is to 0, the fewer terms are required. | |
205 function MathLog1p(x) { | |
206 if (!IS_NUMBER(x)) x = NonNumberToNumber(x); | |
207 var xabs = MathAbs(x); | |
208 if (xabs < 1E-7) { | |
209 return x * (1 - x * (1/2)); | |
210 } else if (xabs < 3E-5) { | |
211 return x * (1 - x * (1/2 - x * (1/3))); | |
212 } else if (xabs < 7E-3) { | |
213 return x * (1 - x * (1/2 - x * (1/3 - x * (1/4 - | |
214 x * (1/5 - x * (1/6 - x * (1/7))))))); | |
215 } else { // Use regular log if not close enough to 0. | |
216 return MathLog(1 + x); | |
217 } | |
218 } | |
219 | |
220 | |
221 function ExtendMath() { | |
222 %CheckIsBootstrapping(); | |
223 | |
224 // Set up the non-enumerable functions on the Math object. | |
225 InstallFunctions($Math, DONT_ENUM, $Array( | |
226 "sign", MathSign, | |
227 "trunc", MathTrunc, | |
228 "sinh", MathSinh, | |
229 "cosh", MathCosh, | |
230 "tanh", MathTanh, | |
231 "asinh", MathAsinh, | |
232 "acosh", MathAcosh, | |
233 "atanh", MathAtanh, | |
234 "log10", MathLog10, | |
235 "log2", MathLog2, | |
236 "hypot", MathHypot, | |
237 "fround", MathFroundJS, | |
238 "clz32", MathClz32, | |
239 "cbrt", MathCbrt, | |
240 "log1p", MathLog1p, | |
241 "expm1", MathExpm1 | |
242 )); | |
243 } | |
244 | |
245 | |
246 ExtendMath(); | |
OLD | NEW |