OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 "use strict"; | 5 "use strict"; |
6 | 6 |
7 // This file relies on the fact that the following declarations have been made | 7 // This file relies on the fact that the following declarations have been made |
8 // in runtime.js: | 8 // in runtime.js: |
9 // var $Object = global.Object; | 9 // var $Object = global.Object; |
10 | 10 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
49 // ToNumber (valueOf) is called. | 49 // ToNumber (valueOf) is called. |
50 function MathAtan2JS(y, x) { | 50 function MathAtan2JS(y, x) { |
51 return %MathAtan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x)); | 51 return %MathAtan2(TO_NUMBER_INLINE(y), TO_NUMBER_INLINE(x)); |
52 } | 52 } |
53 | 53 |
54 // ECMA 262 - 15.8.2.6 | 54 // ECMA 262 - 15.8.2.6 |
55 function MathCeil(x) { | 55 function MathCeil(x) { |
56 return -MathFloor(-x); | 56 return -MathFloor(-x); |
57 } | 57 } |
58 | 58 |
59 // ECMA 262 - 15.8.2.7 | |
60 function MathCos(x) { | |
61 x = MathAbs(x); // Convert to number and get rid of -0. | |
62 return TrigonometricInterpolation(x, 1); | |
63 } | |
64 | |
65 // ECMA 262 - 15.8.2.8 | 59 // ECMA 262 - 15.8.2.8 |
66 function MathExp(x) { | 60 function MathExp(x) { |
67 return %MathExpRT(TO_NUMBER_INLINE(x)); | 61 return %MathExpRT(TO_NUMBER_INLINE(x)); |
68 } | 62 } |
69 | 63 |
70 // ECMA 262 - 15.8.2.9 | 64 // ECMA 262 - 15.8.2.9 |
71 function MathFloor(x) { | 65 function MathFloor(x) { |
72 x = TO_NUMBER_INLINE(x); | 66 x = TO_NUMBER_INLINE(x); |
73 // It's more common to call this with a positive number that's out | 67 // It's more common to call this with a positive number that's out |
74 // of range than negative numbers; check the upper bound first. | 68 // of range than negative numbers; check the upper bound first. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 var x = ((r0 << 16) + (r1 & 0xFFFF)) | 0; | 151 var x = ((r0 << 16) + (r1 & 0xFFFF)) | 0; |
158 // Division by 0x100000000 through multiplication by reciprocal. | 152 // Division by 0x100000000 through multiplication by reciprocal. |
159 return (x < 0 ? (x + 0x100000000) : x) * 2.3283064365386962890625e-10; | 153 return (x < 0 ? (x + 0x100000000) : x) * 2.3283064365386962890625e-10; |
160 } | 154 } |
161 | 155 |
162 // ECMA 262 - 15.8.2.15 | 156 // ECMA 262 - 15.8.2.15 |
163 function MathRound(x) { | 157 function MathRound(x) { |
164 return %RoundNumber(TO_NUMBER_INLINE(x)); | 158 return %RoundNumber(TO_NUMBER_INLINE(x)); |
165 } | 159 } |
166 | 160 |
167 // ECMA 262 - 15.8.2.16 | |
168 function MathSin(x) { | |
169 x = x * 1; // Convert to number and deal with -0. | |
170 if (%_IsMinusZero(x)) return x; | |
171 return TrigonometricInterpolation(x, 0); | |
172 } | |
173 | |
174 // ECMA 262 - 15.8.2.17 | 161 // ECMA 262 - 15.8.2.17 |
175 function MathSqrt(x) { | 162 function MathSqrt(x) { |
176 return %_MathSqrtRT(TO_NUMBER_INLINE(x)); | 163 return %_MathSqrtRT(TO_NUMBER_INLINE(x)); |
177 } | 164 } |
178 | 165 |
179 // ECMA 262 - 15.8.2.18 | |
180 function MathTan(x) { | |
181 return MathSin(x) / MathCos(x); | |
182 } | |
183 | |
184 // Non-standard extension. | 166 // Non-standard extension. |
185 function MathImul(x, y) { | 167 function MathImul(x, y) { |
186 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); | 168 return %NumberImul(TO_NUMBER_INLINE(x), TO_NUMBER_INLINE(y)); |
187 } | 169 } |
188 | 170 |
189 | 171 // ------------------------------------------------------------------- |
190 var kInversePiHalf = 0.636619772367581343; // 2 / pi | 172 |
191 var kInversePiHalfS26 = 9.48637384723993156e-9; // 2 / pi / (2^26) | 173 // A straightforward translation of fdlibm routines for sin, cos, and |
192 var kS26 = 1 << 26; | 174 // tan, by Raymond Toy (rtoy@google.com). |
193 var kTwoStepThreshold = 1 << 27; | 175 |
194 // pi / 2 rounded up | 176 // ==================================================== |
195 var kPiHalf = 1.570796326794896780; // 0x192d4454fb21f93f | 177 // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
196 // We use two parts for pi/2 to emulate a higher precision. | 178 // |
197 // pi_half_1 only has 26 significant bits for mantissa. | 179 // Developed at SunSoft, a Sun Microsystems, Inc. business. |
198 // Note that pi_half > pi_half_1 + pi_half_2 | 180 // Permission to use, copy, modify, and distribute this |
199 var kPiHalf1 = 1.570796325802803040; // 0x00000054fb21f93f | 181 // software is freely granted, provided that this notice |
200 var kPiHalf2 = 9.920935796805404252e-10; // 0x3326a611460b113e | 182 // is preserved. |
201 | 183 // ==================================================== |
202 var kSamples; // Initialized to a number during genesis. | 184 |
203 var kIndexConvert; // Initialized to kSamples / (pi/2) during genesis. | 185 // Initialized to a Float64Array during genesis and is not writable. |
204 var kSinTable; // Initialized to a Float64Array during genesis. | 186 var kTrig; |
205 var kCosXIntervalTable; // Initialized to a Float64Array during genesis. | 187 |
206 | 188 macro REMPIO2(X) |
Raymond Toy
2014/07/24 18:08:44
Does this have to be a macro? Dropping this big ch
Yang
2014/07/28 11:28:59
Yes. Calling a function with double arguments in V
Raymond Toy
2014/07/30 19:55:04
Ok, that's not too surprising if your tests stress
| |
207 // This implements sine using the following algorithm. | 189 var n, y0, y1; |
208 // 1) Multiplication takes care of to-number conversion. | 190 var hx = %_DoubleHi(X); |
209 // 2) Reduce x to the first quadrant [0, pi/2]. | 191 var ix = hx & 0x7fffffff; |
210 // Conveniently enough, in case of +/-Infinity, we get NaN. | 192 |
211 // Note that we try to use only 26 instead of 52 significant bits for | 193 if (ix < 0x4002d97c) { |
212 // mantissa to avoid rounding errors when multiplying. For very large | 194 // |X| ~< 3*pi/4, special case with n = +/- 1 |
213 // input we therefore have additional steps. | 195 if (hx > 0) { |
214 // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant. | 196 var z = X - kTrig[1]; |
Raymond Toy
2014/07/24 16:51:11
Readability would be improved if the kTrig values
Yang
2014/07/28 11:28:59
That is true. However, given that we currently don
Raymond Toy
2014/07/30 19:55:04
Could you give symbolic names for the indices? So
Yang
2014/08/01 07:29:55
Done with macros
| |
215 // 4) Do a table lookup for the closest samples to the left and right of x. | 197 if (ix != 0x3ff921fb) { |
216 // 5) Find the derivatives at those sampling points by table lookup: | 198 // 33+53 bit pi is good enough |
217 // dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2]. | 199 y0 = z - kTrig[2]; |
218 // 6) Use cubic spline interpolation to approximate sin(x). | 200 y1 = (z - y0) - kTrig[2]; |
219 // 7) Negate the result if x was in the 3rd or 4th quadrant. | 201 } else { |
220 // 8) Get rid of -0 by adding 0. | 202 // near pi/2, use 33+33+53 bit pi |
221 function TrigonometricInterpolation(x, phase) { | 203 z -= kTrig[3]; |
222 if (x < 0 || x > kPiHalf) { | 204 y0 = z - kTrig[4]; |
223 var multiple; | 205 y1 = (z - y0) - kTrig[4]; |
224 while (x < -kTwoStepThreshold || x > kTwoStepThreshold) { | 206 } |
225 // Let's assume this loop does not terminate. | 207 n = 1; |
226 // All numbers x in each loop forms a set S. | 208 } else { |
227 // (1) abs(x) > 2^27 for all x in S. | 209 // Negative X |
228 // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1 | 210 var z = X + kTrig[1]; |
229 // (3) multiple is rounded down in 2^26 steps, so the rounding error is | 211 if (ix != 0x3ff921fb) { |
230 // at most max(ulp, 2^26). | 212 // 33+53 bit pi is good enough |
231 // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least | 213 y0 = z + kTrig[2]; |
232 // (1-pi/4)x | 214 y1 = (z - y0) + kTrig[2]; |
233 // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4. | 215 } else { |
234 // Note that this difference cannot be simply rounded off. | 216 // near pi/2, use 33+33+53 bit pi |
235 // Set S cannot exist since (5) violates (1). Loop must terminate. | 217 z += kTrig[3]; |
236 multiple = MathFloor(x * kInversePiHalfS26) * kS26; | 218 y0 = z + kTrig[4]; |
237 x = x - multiple * kPiHalf1 - multiple * kPiHalf2; | 219 y1 = (z - y0) + kTrig[4]; |
238 } | 220 } |
239 multiple = MathFloor(x * kInversePiHalf); | 221 n = -1; |
240 x = x - multiple * kPiHalf1 - multiple * kPiHalf2; | 222 } |
241 phase += multiple; | 223 } else if (ix <= 0x413921fb) { |
242 } | 224 // |X| ~<= 2^19*(pi/2), medium size |
243 var double_index = x * kIndexConvert; | 225 var t = MathAbs(X); |
244 if (phase & 1) double_index = kSamples - double_index; | 226 n = (t * kTrig[0] + 0.5) | 0; |
245 var index = double_index | 0; | 227 var r = t - n * kTrig[1]; |
246 var t1 = double_index - index; | 228 var w = n * kTrig[2]; |
247 var t2 = 1 - t1; | 229 // First round good to 85 bit |
248 var y1 = kSinTable[index]; | 230 y0 = r - w; |
249 var y2 = kSinTable[index + 1]; | 231 if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) { |
Raymond Toy
2014/07/30 19:55:04
It would certainly be good to document what this i
Yang
2014/08/01 07:29:55
I don't think we should be spending time documenti
Raymond Toy
2014/08/01 14:06:00
I would agree if this were in fact the original co
| |
250 var dy = y2 - y1; | 232 // 2nd iteration needed, good to 118 |
251 return (t2 * y1 + t1 * y2 + | 233 t = r; |
252 t1 * t2 * ((kCosXIntervalTable[index] - dy) * t2 + | 234 w = n * kTrig[3]; |
253 (dy - kCosXIntervalTable[index + 1]) * t1)) | 235 r = t - w; |
254 * (1 - (phase & 2)) + 0; | 236 w = n * kTrig[4] - ((t - r) - w); |
255 } | 237 y0 = r - w; |
256 | 238 if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) { |
Raymond Toy
2014/07/30 19:55:03
Same comment as for line 231.
Yang
2014/08/01 07:29:55
Acknowledged.
| |
257 | 239 // 3rd iteration needed. 151 bits accuracy |
240 t = r; | |
241 w = n * kTrig[5]; | |
242 r = t - w; | |
243 w = n * kTrig[6] - ((t - r) - w); | |
244 y0 = r - w; | |
245 } | |
246 } | |
247 y1 = (r - y0) - w; | |
248 if (hx < 0) { | |
249 n = -n; | |
250 y0 = -y0; | |
251 y1 = -y1; | |
252 } | |
253 } else { | |
254 // Need to do full Payne-Hanek reduction here! | |
255 var r = %RemPiO2(X); | |
256 n = r[0]; | |
257 y0 = r[1]; | |
258 y1 = r[2]; | |
259 } | |
260 endmacro | |
261 | |
262 // Sine for [-pi/4, pi/4], pi/4 ~ 0.7854 | |
Raymond Toy
2014/07/24 16:51:11
I think it would be beneficial to add the original
Yang
2014/07/28 11:28:59
Done.
| |
263 macro RETURN_KERNELSIN(X0, X1, SIGN) | |
264 var z = X0 * X0; | |
265 var v = z * X0; | |
266 var r = kTrig[8] + z * (kTrig[9] + z * (kTrig[10] + | |
267 z * (kTrig[11] + z * kTrig[12]))); | |
268 return (X0 - ((z * (0.5 * X1 - v * r) - X1) - v * kTrig[7])) SIGN; | |
Raymond Toy
2014/07/24 16:51:11
The original kernel_sin function had a slight opti
Yang
2014/07/28 11:28:59
I think I checked this. And I rechecked. In neithe
Raymond Toy
2014/07/30 19:55:04
Fair enough.
| |
269 endmacro | |
Raymond Toy
2014/07/24 16:51:12
I think readability would be enhanced if you had a
Yang
2014/07/28 11:28:59
Acknowledged.
| |
270 | |
271 // Cosine for [-pi/4, pi/4], pi/4 ~ 0.7854 | |
272 macro RETURN_KERNELCOS(X0, X1, SIGN) | |
273 var ix = %_DoubleHi(X0) & 0x7fffffff; | |
274 var z = X0 * X0; | |
275 var r = z * (kTrig[13] + z * (kTrig[14] + z * (kTrig[15] + | |
Raymond Toy
2014/07/24 16:51:11
Can we use a separate array for kTrig values here
Yang
2014/07/28 11:28:59
There is not much readability to be gained here im
Raymond Toy
2014/07/30 19:55:04
I have no problems with the various random constan
Yang
2014/08/01 07:29:55
Done with macros.
| |
276 z * (kTrig[16] + z * (kTrig[17] + z * kTrig[18]))))); | |
277 if (ix < 0x3fd33333) { | |
Raymond Toy
2014/07/30 19:55:03
Add comment that ix < 0x3fd33333 is testing for |x
Yang
2014/08/01 07:29:55
Done.
| |
278 return (1 - (0.5 * z - (z * r - X0 * X1))) SIGN; | |
279 } else { | |
280 var qx; | |
281 if (ix > 0x3fe90000) { | |
Raymond Toy
2014/07/24 16:51:12
I think it's really useful to include the fdlibm c
Yang
2014/07/28 11:28:59
imo the comment in your port doesn't explain much
Raymond Toy
2014/07/30 19:55:03
No, but at least it makes it clear that ix > 0x3fe
Yang
2014/08/01 07:29:55
Done.
| |
282 qx = 0.28125; | |
283 } else { | |
284 qx = %_ConstructDouble(%_DoubleHi(0.25 * X0), 0); | |
285 } | |
286 var hz = 0.5 * z - qx; | |
287 return (1 - qx - (hz - (z * r - X0 * X1))) SIGN; | |
288 } | |
289 endmacro | |
290 | |
291 // Tangent for [-pi/4, pi/4], pi/4 ~ 0.7854 | |
Raymond Toy
2014/07/24 16:51:12
Include original fdlibm comment. Without that it's
Yang
2014/07/28 11:28:59
Done.
| |
292 function KernelTan(x, y, returnTan) { | |
293 var z; | |
294 var w; | |
295 var hx = %_DoubleHi(x); | |
296 var ix = hx & 0x7fffffff; | |
297 | |
298 if (ix < 0x3e300000) { | |
299 // x < 2^-28 | |
300 if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) { | |
Raymond Toy
2014/07/30 19:55:04
This might be more obvious if we said abs(x) == 0
Yang
2014/08/01 07:29:55
I don't think I changed anything here from your po
| |
301 return 1 / MathAbs(x); | |
302 } else { | |
303 if (returnTan == 1) { | |
304 return x; | |
305 } else { | |
306 // Compute -1/(x + y) carefully | |
307 var w = x + y; | |
308 var z = %_ConstructDouble(%_DoubleHi(w), 0); | |
309 var v = y - (z - x); | |
310 var a = -1 / w; | |
311 var t = %_ConstructDouble(%_DoubleHi(a), 0); | |
312 var s = 1 + t * z; | |
313 return t + a * (s + t * v); | |
314 } | |
315 } | |
316 } | |
317 if (ix >= 0x3fe59429) { | |
318 // |x| > .6744 | |
319 if (x < 0) { | |
320 x = -x; | |
321 y = -y; | |
322 } | |
323 z = kTrig[32] - x; | |
324 w = kTrig[33] - y; | |
325 x = z + w; | |
326 y = 0; | |
327 } | |
328 z = x * x; | |
329 w = z * z; | |
330 | |
331 var r = kTrig[20] + w * (kTrig[22] + w * (kTrig[24] + | |
Raymond Toy
2014/07/24 16:51:11
Can we use a separate array for the coefficients i
Yang
2014/07/28 11:28:59
Acknowledged.
Raymond Toy
2014/07/30 19:55:04
Add back the comment. This would be unexpected fro
| |
332 w * (kTrig[26] + w * (kTrig[28] + w * kTrig[30])))); | |
333 var v = z * (kTrig[21] + w * (kTrig[23] + w * (kTrig[25] + | |
334 w * (kTrig[27] + w * (kTrig[29] + w * kTrig[31]))))); | |
335 var s = z * x; | |
336 r = y + z * (s * (r + v) + y); | |
337 r = r + kTrig[19] * s; | |
338 w = x + r; | |
339 if (ix >= 0x3fe59428) { | |
Raymond Toy
2014/07/30 19:55:04
Document what 0x3fe59428 is.
| |
340 return (1 - ((hx >> 30) & 2)) * | |
Raymond Toy
2014/07/30 19:55:04
Describe what ((hx >> 30) & 2) is doing.
| |
341 (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r))); | |
342 } | |
343 if (returnTan == 1) { | |
344 return w; | |
345 } else { | |
346 z = %_ConstructDouble(%_DoubleHi(w), 0); | |
347 v = r - (z - x); | |
348 var a = -1 / w; | |
349 var t = %_ConstructDouble(%_DoubleHi(a), 0); | |
350 s = 1 + t * z; | |
351 return t + a * (s + t * v); | |
352 } | |
353 } | |
354 | |
355 function MathSinSlow(x) { | |
Raymond Toy
2014/07/24 16:51:12
I think MathSinAccurate is a better name. Or maybe
Yang
2014/07/28 11:28:59
This function is not more accurate. The difference
Raymond Toy
2014/07/30 19:55:03
Sure, that makes sense.
| |
356 REMPIO2(x); | |
357 var sign = 1 - (n & 2); | |
358 if (n & 1) { | |
359 RETURN_KERNELCOS(y0, y1, * sign); | |
360 } else { | |
361 RETURN_KERNELSIN(y0, y1, * sign); | |
362 } | |
363 } | |
364 | |
365 function MathCosSlow(x) { | |
Raymond Toy
2014/07/24 16:51:11
Similar comment as MathSinSlow.
Yang
2014/07/28 11:28:59
Acknowledged.
| |
366 REMPIO2(x); | |
367 if (n & 1) { | |
368 var sign = (n & 2) - 1; | |
369 RETURN_KERNELSIN(y0, y1, * sign); | |
370 } else { | |
371 var sign = 1 - (n & 2); | |
372 RETURN_KERNELCOS(y0, y1, * sign); | |
373 } | |
374 } | |
375 | |
376 // ECMA 262 - 15.8.2.16 | |
377 function MathSin(x) { | |
378 x = x * 1; // Convert to number. | |
379 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | |
380 // |x| < pi/4, approximately. No reduction needed. | |
381 if (%_IsMinusZero(x)) return x; | |
Raymond Toy
2014/07/24 18:08:44
Is this test for -0 necessary? KERNELSIN should be
Yang
2014/07/28 11:28:59
You are right. Removed.
| |
382 RETURN_KERNELSIN(x, 0, /* empty */); | |
383 } | |
384 return MathSinSlow(x); | |
385 } | |
386 | |
387 // ECMA 262 - 15.8.2.7 | |
388 function MathCos(x) { | |
389 x = x * 1; // Convert to number. | |
390 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | |
391 // |x| < pi/4, approximately. No reduction needed. | |
392 RETURN_KERNELCOS(x, 0, /* empty */); | |
393 } | |
394 return MathCosSlow(x); | |
395 } | |
396 | |
397 // ECMA 262 - 15.8.2.18 | |
398 function MathTan(x) { | |
399 x = x * 1; // Convert to number. | |
400 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | |
401 // |x| < pi/4, approximately. No reduction needed. | |
402 if (%_IsMinusZero(x)) return x; | |
Raymond Toy
2014/07/24 18:08:43
Is this test for -0 really necessary? If KernelTan
Yang
2014/07/28 11:28:59
Done.
| |
403 return KernelTan(x, 0, 1); | |
404 } | |
405 REMPIO2(x); | |
406 return KernelTan(y0, y1, (n & 1) ? -1 : 1); | |
407 } | |
408 | |
409 | |
258 // ES6 draft 09-27-13, section 20.2.2.28. | 410 // ES6 draft 09-27-13, section 20.2.2.28. |
259 function MathSign(x) { | 411 function MathSign(x) { |
260 x = TO_NUMBER_INLINE(x); | 412 x = TO_NUMBER_INLINE(x); |
261 if (x > 0) return 1; | 413 if (x > 0) return 1; |
262 if (x < 0) return -1; | 414 if (x < 0) return -1; |
263 if (x === 0) return x; | 415 if (x === 0) return x; |
264 return NAN; | 416 return NAN; |
265 } | 417 } |
266 | 418 |
267 | 419 |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
530 "clz32", MathClz32, | 682 "clz32", MathClz32, |
531 "cbrt", MathCbrt, | 683 "cbrt", MathCbrt, |
532 "log1p", MathLog1p, | 684 "log1p", MathLog1p, |
533 "expm1", MathExpm1 | 685 "expm1", MathExpm1 |
534 )); | 686 )); |
535 | 687 |
536 %SetInlineBuiltinFlag(MathCeil); | 688 %SetInlineBuiltinFlag(MathCeil); |
537 %SetInlineBuiltinFlag(MathRandom); | 689 %SetInlineBuiltinFlag(MathRandom); |
538 %SetInlineBuiltinFlag(MathSin); | 690 %SetInlineBuiltinFlag(MathSin); |
539 %SetInlineBuiltinFlag(MathCos); | 691 %SetInlineBuiltinFlag(MathCos); |
540 %SetInlineBuiltinFlag(MathTan); | |
541 %SetInlineBuiltinFlag(TrigonometricInterpolation); | |
542 } | 692 } |
543 | 693 |
544 SetUpMath(); | 694 SetUpMath(); |
OLD | NEW |