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 var kTrig; // Initialized to a Float64Array during genesis. |
204 var kSinTable; // Initialized to a Float64Array during genesis. | 186 |
205 var kCosXIntervalTable; // Initialized to a Float64Array during genesis. | 187 macro REMPIO2(X) |
206 | 188 var n, y0, y1; |
207 // This implements sine using the following algorithm. | 189 var hx = %_DoubleHi(X); |
208 // 1) Multiplication takes care of to-number conversion. | 190 var ix = hx & 0x7fffffff; |
209 // 2) Reduce x to the first quadrant [0, pi/2]. | 191 |
210 // Conveniently enough, in case of +/-Infinity, we get NaN. | 192 if (ix < 0x4002d97c) { |
211 // Note that we try to use only 26 instead of 52 significant bits for | 193 // |X| ~< 3*pi/4, special case with n = +/- 1 |
212 // mantissa to avoid rounding errors when multiplying. For very large | 194 if (hx > 0) { |
213 // input we therefore have additional steps. | 195 var z = X - kTrig[1]; |
214 // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant. | 196 if (ix != 0x3ff921fb) { |
215 // 4) Do a table lookup for the closest samples to the left and right of x. | 197 // 33+53 bit pi is good enough |
216 // 5) Find the derivatives at those sampling points by table lookup: | 198 y0 = z - kTrig[2]; |
217 // dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2]. | 199 y1 = (z - y0) - kTrig[2]; |
218 // 6) Use cubic spline interpolation to approximate sin(x). | 200 } else { |
219 // 7) Negate the result if x was in the 3rd or 4th quadrant. | 201 // near pi/2, use 33+33+53 bit pi |
220 // 8) Get rid of -0 by adding 0. | 202 z -= kTrig[3]; |
221 function TrigonometricInterpolation(x, phase) { | 203 y0 = z - kTrig[4]; |
222 if (x < 0 || x > kPiHalf) { | 204 y1 = (z - y0) - kTrig[4]; |
223 var multiple; | 205 } |
224 while (x < -kTwoStepThreshold || x > kTwoStepThreshold) { | 206 n = 1; |
225 // Let's assume this loop does not terminate. | 207 } else { |
226 // All numbers x in each loop forms a set S. | 208 // Negative X |
227 // (1) abs(x) > 2^27 for all x in S. | 209 var z = X + kTrig[1]; |
228 // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1 | 210 if (ix != 0x3ff921fb) { |
229 // (3) multiple is rounded down in 2^26 steps, so the rounding error is | 211 // 33+53 bit pi is good enough |
230 // at most max(ulp, 2^26). | 212 y0 = z + kTrig[2]; |
231 // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least | 213 y1 = (z - y0) + kTrig[2]; |
232 // (1-pi/4)x | 214 } else { |
233 // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4. | 215 // near pi/2, use 33+33+53 bit pi |
234 // Note that this difference cannot be simply rounded off. | 216 z += kTrig[3]; |
235 // Set S cannot exist since (5) violates (1). Loop must terminate. | 217 y0 = z + kTrig[4]; |
236 multiple = MathFloor(x * kInversePiHalfS26) * kS26; | 218 y1 = (z - y0) + kTrig[4]; |
237 x = x - multiple * kPiHalf1 - multiple * kPiHalf2; | 219 } |
238 } | 220 n = -1; |
239 multiple = MathFloor(x * kInversePiHalf); | 221 } |
240 x = x - multiple * kPiHalf1 - multiple * kPiHalf2; | 222 } else if (ix <= 0x413921fb) { |
241 phase += multiple; | 223 // |X| ~<= 2^19*(pi/2), medium size |
242 } | 224 var t = MathAbs(X); |
243 var double_index = x * kIndexConvert; | 225 n = (t * kTrig[0] + 0.5) | 0; |
244 if (phase & 1) double_index = kSamples - double_index; | 226 var r = t - n * kTrig[1]; |
245 var index = double_index | 0; | 227 var w = n * kTrig[2]; |
246 var t1 = double_index - index; | 228 // First round good to 85 bit |
247 var t2 = 1 - t1; | 229 y0 = r - w; |
248 var y1 = kSinTable[index]; | 230 if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x1000000) { |
249 var y2 = kSinTable[index + 1]; | 231 // 2nd iteration needed, good to 118 |
250 var dy = y2 - y1; | 232 t = r; |
251 return (t2 * y1 + t1 * y2 + | 233 w = n * kTrig[3]; |
252 t1 * t2 * ((kCosXIntervalTable[index] - dy) * t2 + | 234 r = t - w; |
253 (dy - kCosXIntervalTable[index + 1]) * t1)) | 235 w = n * kTrig[4] - ((t - r) - w); |
254 * (1 - (phase & 2)) + 0; | 236 y0 = r - w; |
255 } | 237 if (ix - (%_DoubleHi(y0) & 0x7ff00000) > 0x3100000) { |
256 | 238 // 3rd iteration needed. 151 bits accuracy |
257 | 239 t = r; |
| 240 w = n * kTrig[5]; |
| 241 r = t - w; |
| 242 w = n * kTrig[6] - ((t - r) - w); |
| 243 y0 = r - w; |
| 244 } |
| 245 } |
| 246 y1 = (r - y0) - w; |
| 247 if (hx < 0) { |
| 248 n = -n; |
| 249 y0 = -y0; |
| 250 y1 = -y1; |
| 251 } |
| 252 } else { |
| 253 // Need to do full Payne-Hanek reduction here! |
| 254 var r = %RemPiO2(X); |
| 255 n = r[0]; |
| 256 y0 = r[1]; |
| 257 y1 = r[2]; |
| 258 } |
| 259 endmacro |
| 260 |
| 261 // Sine for [-pi/4, pi/4], pi/4 ~ 0.7854 |
| 262 macro RETURN_KERNELSIN(X0, X1, SIGN) |
| 263 var z = X0 * X0; |
| 264 var v = z * X0; |
| 265 var r = kTrig[8] + z * (kTrig[9] + z * (kTrig[10] + |
| 266 z * (kTrig[11] + z * kTrig[12]))); |
| 267 return (X0 - ((z * (0.5 * X1 - v * r) - X1) - v * kTrig[7])) SIGN; |
| 268 endmacro |
| 269 |
| 270 // Cosine for [-pi/4, pi/4], pi/4 ~ 0.7854 |
| 271 macro RETURN_KERNELCOS(X0, X1, SIGN) |
| 272 var ix = %_DoubleHi(X0) & 0x7fffffff; |
| 273 var z = X0 * X0; |
| 274 var r = z * (kTrig[13] + z * (kTrig[14] + z * (kTrig[15] + |
| 275 z * (kTrig[16] + z * (kTrig[17] + z * kTrig[18]))))); |
| 276 if (ix < 0x3fd33333) { |
| 277 return (1 - (0.5 * z - (z * r - X0 * X1))) SIGN; |
| 278 } else { |
| 279 var qx; |
| 280 if (ix > 0x3fe90000) { |
| 281 qx = 0.28125; |
| 282 } else { |
| 283 qx = %_ConstructDouble(%_DoubleHi(0.25 * X0), 0); |
| 284 } |
| 285 var hz = 0.5 * z - qx; |
| 286 return (1 - qx - (hz - (z * r - X0 * X1))) SIGN; |
| 287 } |
| 288 endmacro |
| 289 |
| 290 // Tangent for [-pi/4, pi/4], pi/4 ~ 0.7854 |
| 291 function KernelTan(x, y, returnTan) { |
| 292 var z; |
| 293 var w; |
| 294 var hx = %_DoubleHi(x); |
| 295 var ix = hx & 0x7fffffff; |
| 296 |
| 297 if (ix < 0x3e300000) { |
| 298 // x < 2^-28 |
| 299 if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) { |
| 300 return 1 / MathAbs(x); |
| 301 } else { |
| 302 if (returnTan == 1) { |
| 303 return x; |
| 304 } else { |
| 305 // Compute -1/(x + y) carefully |
| 306 var w = x + y; |
| 307 var z = %_ConstructDouble(%_DoubleHi(w), 0); |
| 308 var v = y - (z - x); |
| 309 var a = -1 / w; |
| 310 var t = %_ConstructDouble(%_DoubleHi(a), 0); |
| 311 var s = 1 + t * z; |
| 312 return t + a * (s + t * v); |
| 313 } |
| 314 } |
| 315 } |
| 316 if (ix >= 0x3fe59429) { |
| 317 // |x| > .6744 |
| 318 if (x < 0) { |
| 319 x = -x; |
| 320 y = -y; |
| 321 } |
| 322 z = kTrig[32] - x; |
| 323 w = kTrig[33] - y; |
| 324 x = z + w; |
| 325 y = 0; |
| 326 } |
| 327 z = x * x; |
| 328 w = z * z; |
| 329 |
| 330 var r = kTrig[20] + w * (kTrig[22] + w * (kTrig[24] + |
| 331 w * (kTrig[26] + w * (kTrig[28] + w * kTrig[30])))); |
| 332 var v = z * (kTrig[21] + w * (kTrig[23] + w * (kTrig[25] + |
| 333 w * (kTrig[27] + w * (kTrig[29] + w * kTrig[31]))))); |
| 334 var s = z * x; |
| 335 r = y + z * (s * (r + v) + y); |
| 336 r = r + kTrig[19] * s; |
| 337 w = x + r; |
| 338 if (ix >= 0x3fe59428) { |
| 339 return (1 - ((hx >> 30) & 2)) * |
| 340 (returnTan - 2.0 * (x - (w * w / (w + returnTan) - r))); |
| 341 } |
| 342 if (returnTan == 1) { |
| 343 return w; |
| 344 } else { |
| 345 z = %_ConstructDouble(%_DoubleHi(w), 0); |
| 346 v = r - (z - x); |
| 347 var a = -1 / w; |
| 348 var t = %_ConstructDouble(%_DoubleHi(a), 0); |
| 349 s = 1 + t * z; |
| 350 return t + a * (s + t * v); |
| 351 } |
| 352 } |
| 353 |
| 354 function MathSinSlow(x) { |
| 355 REMPIO2(x); |
| 356 var sign = 1 - (n & 2); |
| 357 if (n & 1) { |
| 358 RETURN_KERNELCOS(y0, y1, * sign); |
| 359 } else { |
| 360 RETURN_KERNELSIN(y0, y1, * sign); |
| 361 } |
| 362 } |
| 363 |
| 364 function MathCosSlow(x) { |
| 365 REMPIO2(x); |
| 366 if (n & 1) { |
| 367 var sign = (n & 2) - 1; |
| 368 RETURN_KERNELSIN(y0, y1, * sign); |
| 369 } else { |
| 370 var sign = 1 - (n & 2); |
| 371 RETURN_KERNELCOS(y0, y1, * sign); |
| 372 } |
| 373 } |
| 374 |
| 375 // ECMA 262 - 15.8.2.16 |
| 376 function MathSin(x) { |
| 377 x = x * 1; // Convert to number. |
| 378 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { |
| 379 // |x| < pi/4, approximately. No reduction needed. |
| 380 if (%_IsMinusZero(x)) return x; |
| 381 RETURN_KERNELSIN(x, 0, /* empty */); |
| 382 } |
| 383 return MathSinSlow(x); |
| 384 } |
| 385 |
| 386 // ECMA 262 - 15.8.2.7 |
| 387 function MathCos(x) { |
| 388 x = x * 1; // Convert to number. |
| 389 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { |
| 390 // |x| < pi/4, approximately. No reduction needed. |
| 391 RETURN_KERNELCOS(x, 0, /* empty */); |
| 392 } |
| 393 return MathCosSlow(x); |
| 394 } |
| 395 |
| 396 // ECMA 262 - 15.8.2.18 |
| 397 function MathTan(x) { |
| 398 x = x * 1; // Convert to number. |
| 399 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { |
| 400 // |x| < pi/4, approximately. No reduction needed. |
| 401 if (%_IsMinusZero(x)) return x; |
| 402 return KernelTan(x, 0, 1); |
| 403 } |
| 404 REMPIO2(x); |
| 405 return KernelTan(y0, y1, (n & 1) ? -1 : 1); |
| 406 } |
| 407 |
| 408 |
258 // ES6 draft 09-27-13, section 20.2.2.28. | 409 // ES6 draft 09-27-13, section 20.2.2.28. |
259 function MathSign(x) { | 410 function MathSign(x) { |
260 x = TO_NUMBER_INLINE(x); | 411 x = TO_NUMBER_INLINE(x); |
261 if (x > 0) return 1; | 412 if (x > 0) return 1; |
262 if (x < 0) return -1; | 413 if (x < 0) return -1; |
263 if (x === 0) return x; | 414 if (x === 0) return x; |
264 return NAN; | 415 return NAN; |
265 } | 416 } |
266 | 417 |
267 | 418 |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 "clz32", MathClz32, | 681 "clz32", MathClz32, |
531 "cbrt", MathCbrt, | 682 "cbrt", MathCbrt, |
532 "log1p", MathLog1p, | 683 "log1p", MathLog1p, |
533 "expm1", MathExpm1 | 684 "expm1", MathExpm1 |
534 )); | 685 )); |
535 | 686 |
536 %SetInlineBuiltinFlag(MathCeil); | 687 %SetInlineBuiltinFlag(MathCeil); |
537 %SetInlineBuiltinFlag(MathRandom); | 688 %SetInlineBuiltinFlag(MathRandom); |
538 %SetInlineBuiltinFlag(MathSin); | 689 %SetInlineBuiltinFlag(MathSin); |
539 %SetInlineBuiltinFlag(MathCos); | 690 %SetInlineBuiltinFlag(MathCos); |
540 %SetInlineBuiltinFlag(MathTan); | |
541 %SetInlineBuiltinFlag(TrigonometricInterpolation); | |
542 } | 691 } |
543 | 692 |
544 SetUpMath(); | 693 SetUpMath(); |
OLD | NEW |