OLD | NEW |
1 // The following is adapted from fdlibm (http://www.netlib.org/fdlibm), | 1 // The following is adapted from fdlibm (http://www.netlib.org/fdlibm), |
2 // | 2 // |
3 // ==================================================== | 3 // ==================================================== |
4 // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. | 4 // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. |
5 // | 5 // |
6 // Developed at SunSoft, a Sun Microsystems, Inc. business. | 6 // Developed at SunSoft, a Sun Microsystems, Inc. business. |
7 // Permission to use, copy, modify, and distribute this | 7 // Permission to use, copy, modify, and distribute this |
8 // software is freely granted, provided that this notice | 8 // software is freely granted, provided that this notice |
9 // is preserved. | 9 // is preserved. |
10 // ==================================================== | 10 // ==================================================== |
11 // | 11 // |
12 // The original source code covered by the above license above has been | 12 // The original source code covered by the above license above has been |
13 // modified significantly by Google Inc. | 13 // modified significantly by Google Inc. |
14 // Copyright 2014 the V8 project authors. All rights reserved. | 14 // Copyright 2014 the V8 project authors. All rights reserved. |
15 // | 15 // |
16 // The following is a straightforward translation of fdlibm routines for | 16 // The following is a straightforward translation of fdlibm routines |
17 // sin, cos, and tan, by Raymond Toy (rtoy@google.com). | 17 // by Raymond Toy (rtoy@google.com). |
18 | 18 |
19 | 19 |
20 var kTrig; // Initialized to a Float64Array during genesis and is not writable. | 20 var kMath; // Initialized to a Float64Array during genesis and is not writable. |
21 | 21 |
22 const INVPIO2 = kTrig[0]; | 22 const INVPIO2 = kMath[0]; |
23 const PIO2_1 = kTrig[1]; | 23 const PIO2_1 = kMath[1]; |
24 const PIO2_1T = kTrig[2]; | 24 const PIO2_1T = kMath[2]; |
25 const PIO2_2 = kTrig[3]; | 25 const PIO2_2 = kMath[3]; |
26 const PIO2_2T = kTrig[4]; | 26 const PIO2_2T = kMath[4]; |
27 const PIO2_3 = kTrig[5]; | 27 const PIO2_3 = kMath[5]; |
28 const PIO2_3T = kTrig[6]; | 28 const PIO2_3T = kMath[6]; |
29 const PIO4 = kTrig[32]; | 29 const PIO4 = kMath[32]; |
30 const PIO4LO = kTrig[33]; | 30 const PIO4LO = kMath[33]; |
31 | 31 |
32 // Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For | 32 // Compute k and r such that x - k*pi/2 = r where |r| < pi/4. For |
33 // precision, r is returned as two values y0 and y1 such that r = y0 + y1 | 33 // precision, r is returned as two values y0 and y1 such that r = y0 + y1 |
34 // to more than double precision. | 34 // to more than double precision. |
35 macro REMPIO2(X) | 35 macro REMPIO2(X) |
36 var n, y0, y1; | 36 var n, y0, y1; |
37 var hx = %_DoubleHi(X); | 37 var hx = %_DoubleHi(X); |
38 var ix = hx & 0x7fffffff; | 38 var ix = hx & 0x7fffffff; |
39 | 39 |
40 if (ix < 0x4002d97c) { | 40 if (ix < 0x4002d97c) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 // | 126 // |
127 // 3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y | 127 // 3. ieee_sin(X+Y) = ieee_sin(X) + sin'(X')*Y |
128 // ~ ieee_sin(X) + (1-X*X/2)*Y | 128 // ~ ieee_sin(X) + (1-X*X/2)*Y |
129 // For better accuracy, let | 129 // For better accuracy, let |
130 // 3 2 2 2 2 | 130 // 3 2 2 2 2 |
131 // r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6)))) | 131 // r = X *(S2+X *(S3+X *(S4+X *(S5+X *S6)))) |
132 // then 3 2 | 132 // then 3 2 |
133 // sin(x) = X + (S1*X + (X *(r-Y/2)+Y)) | 133 // sin(x) = X + (S1*X + (X *(r-Y/2)+Y)) |
134 // | 134 // |
135 macro KSIN(x) | 135 macro KSIN(x) |
136 kTrig[7+x] | 136 kMath[7+x] |
137 endmacro | 137 endmacro |
138 | 138 |
139 macro RETURN_KERNELSIN(X, Y, SIGN) | 139 macro RETURN_KERNELSIN(X, Y, SIGN) |
140 var z = X * X; | 140 var z = X * X; |
141 var v = z * X; | 141 var v = z * X; |
142 var r = KSIN(1) + z * (KSIN(2) + z * (KSIN(3) + | 142 var r = KSIN(1) + z * (KSIN(2) + z * (KSIN(3) + |
143 z * (KSIN(4) + z * KSIN(5)))); | 143 z * (KSIN(4) + z * KSIN(5)))); |
144 return (X - ((z * (0.5 * Y - v * r) - Y) - v * KSIN(0))) SIGN; | 144 return (X - ((z * (0.5 * Y - v * r) - Y) - v * KSIN(0))) SIGN; |
145 endmacro | 145 endmacro |
146 | 146 |
(...skipping 23 matching lines...) Expand all Loading... |
170 // cos(X+Y) = 1 - (X*X/2 - (r - X*Y)) | 170 // cos(X+Y) = 1 - (X*X/2 - (r - X*Y)) |
171 // For better accuracy when x > 0.3, let qx = |x|/4 with | 171 // For better accuracy when x > 0.3, let qx = |x|/4 with |
172 // the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. | 172 // the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. |
173 // Then | 173 // Then |
174 // cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)). | 174 // cos(X+Y) = (1-qx) - ((X*X/2-qx) - (r-X*Y)). |
175 // Note that 1-qx and (X*X/2-qx) is EXACT here, and the | 175 // Note that 1-qx and (X*X/2-qx) is EXACT here, and the |
176 // magnitude of the latter is at least a quarter of X*X/2, | 176 // magnitude of the latter is at least a quarter of X*X/2, |
177 // thus, reducing the rounding error in the subtraction. | 177 // thus, reducing the rounding error in the subtraction. |
178 // | 178 // |
179 macro KCOS(x) | 179 macro KCOS(x) |
180 kTrig[13+x] | 180 kMath[13+x] |
181 endmacro | 181 endmacro |
182 | 182 |
183 macro RETURN_KERNELCOS(X, Y, SIGN) | 183 macro RETURN_KERNELCOS(X, Y, SIGN) |
184 var ix = %_DoubleHi(X) & 0x7fffffff; | 184 var ix = %_DoubleHi(X) & 0x7fffffff; |
185 var z = X * X; | 185 var z = X * X; |
186 var r = z * (KCOS(0) + z * (KCOS(1) + z * (KCOS(2)+ | 186 var r = z * (KCOS(0) + z * (KCOS(1) + z * (KCOS(2)+ |
187 z * (KCOS(3) + z * (KCOS(4) + z * KCOS(5)))))); | 187 z * (KCOS(3) + z * (KCOS(4) + z * KCOS(5)))))); |
188 if (ix < 0x3fd33333) { // |x| ~< 0.3 | 188 if (ix < 0x3fd33333) { // |x| ~< 0.3 |
189 return (1 - (0.5 * z - (z * r - X * Y))) SIGN; | 189 return (1 - (0.5 * z - (z * r - X * Y))) SIGN; |
190 } else { | 190 } else { |
191 var qx; | 191 var qx; |
192 if (ix > 0x3fe90000) { // |x| > 0.78125 | 192 if (ix > 0x3fe90000) { // |x| > 0.78125 |
193 qx = 0.28125; | 193 qx = 0.28125; |
194 } else { | 194 } else { |
195 qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0); | 195 qx = %_ConstructDouble(%_DoubleHi(0.25 * X), 0); |
196 } | 196 } |
197 var hz = 0.5 * z - qx; | 197 var hz = 0.5 * z - qx; |
198 return (1 - qx - (hz - (z * r - X * Y))) SIGN; | 198 return (1 - qx - (hz - (z * r - X * Y))) SIGN; |
199 } | 199 } |
200 endmacro | 200 endmacro |
201 | 201 |
| 202 |
202 // kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854 | 203 // kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854 |
203 // Input x is assumed to be bounded by ~pi/4 in magnitude. | 204 // Input x is assumed to be bounded by ~pi/4 in magnitude. |
204 // Input y is the tail of x. | 205 // Input y is the tail of x. |
205 // Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1) | 206 // Input k indicates whether ieee_tan (if k = 1) or -1/tan (if k = -1) |
206 // is returned. | 207 // is returned. |
207 // | 208 // |
208 // Algorithm | 209 // Algorithm |
209 // 1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x. | 210 // 1. Since ieee_tan(-x) = -ieee_tan(x), we need only to consider positive x. |
210 // 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0. | 211 // 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0. |
211 // 3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on | 212 // 3. ieee_tan(x) is approximated by a odd polynomial of degree 27 on |
(...skipping 16 matching lines...) Expand all Loading... |
228 // tan(x+y) = x + (T1*x + (x *(r+y)+y)) | 229 // tan(x+y) = x + (T1*x + (x *(r+y)+y)) |
229 // | 230 // |
230 // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then | 231 // 4. For x in [0.67434,pi/4], let y = pi/4 - x, then |
231 // tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y)) | 232 // tan(x) = ieee_tan(pi/4-y) = (1-ieee_tan(y))/(1+ieee_tan(y)) |
232 // = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y))) | 233 // = 1 - 2*(ieee_tan(y) - (ieee_tan(y)^2)/(1+ieee_tan(y))) |
233 // | 234 // |
234 // Set returnTan to 1 for tan; -1 for cot. Anything else is illegal | 235 // Set returnTan to 1 for tan; -1 for cot. Anything else is illegal |
235 // and will cause incorrect results. | 236 // and will cause incorrect results. |
236 // | 237 // |
237 macro KTAN(x) | 238 macro KTAN(x) |
238 kTrig[19+x] | 239 kMath[19+x] |
239 endmacro | 240 endmacro |
240 | 241 |
241 function KernelTan(x, y, returnTan) { | 242 function KernelTan(x, y, returnTan) { |
242 var z; | 243 var z; |
243 var w; | 244 var w; |
244 var hx = %_DoubleHi(x); | 245 var hx = %_DoubleHi(x); |
245 var ix = hx & 0x7fffffff; | 246 var ix = hx & 0x7fffffff; |
246 | 247 |
247 if (ix < 0x3e300000) { // |x| < 2^-28 | 248 if (ix < 0x3e300000) { // |x| < 2^-28 |
248 if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) { | 249 if (((ix | %_DoubleLo(x)) | (returnTan + 1)) == 0) { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 // ECMA 262 - 15.8.2.18 | 348 // ECMA 262 - 15.8.2.18 |
348 function MathTan(x) { | 349 function MathTan(x) { |
349 x = x * 1; // Convert to number. | 350 x = x * 1; // Convert to number. |
350 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { | 351 if ((%_DoubleHi(x) & 0x7fffffff) <= 0x3fe921fb) { |
351 // |x| < pi/4, approximately. No reduction needed. | 352 // |x| < pi/4, approximately. No reduction needed. |
352 return KernelTan(x, 0, 1); | 353 return KernelTan(x, 0, 1); |
353 } | 354 } |
354 REMPIO2(x); | 355 REMPIO2(x); |
355 return KernelTan(y0, y1, (n & 1) ? -1 : 1); | 356 return KernelTan(y0, y1, (n & 1) ? -1 : 1); |
356 } | 357 } |
| 358 |
| 359 // ES6 draft 09-27-13, section 20.2.2.20. |
| 360 // Math.log1p |
| 361 // |
| 362 // Method : |
| 363 // 1. Argument Reduction: find k and f such that |
| 364 // 1+x = 2^k * (1+f), |
| 365 // where sqrt(2)/2 < 1+f < sqrt(2) . |
| 366 // |
| 367 // Note. If k=0, then f=x is exact. However, if k!=0, then f |
| 368 // may not be representable exactly. In that case, a correction |
| 369 // term is need. Let u=1+x rounded. Let c = (1+x)-u, then |
| 370 // log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), |
| 371 // and add back the correction term c/u. |
| 372 // (Note: when x > 2**53, one can simply return log(x)) |
| 373 // |
| 374 // 2. Approximation of log1p(f). |
| 375 // Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) |
| 376 // = 2s + 2/3 s**3 + 2/5 s**5 + ....., |
| 377 // = 2s + s*R |
| 378 // We use a special Reme algorithm on [0,0.1716] to generate |
| 379 // a polynomial of degree 14 to approximate R The maximum error |
| 380 // of this polynomial approximation is bounded by 2**-58.45. In |
| 381 // other words, |
| 382 // 2 4 6 8 10 12 14 |
| 383 // R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s |
| 384 // (the values of Lp1 to Lp7 are listed in the program) |
| 385 // and |
| 386 // | 2 14 | -58.45 |
| 387 // | Lp1*s +...+Lp7*s - R(z) | <= 2 |
| 388 // | | |
| 389 // Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. |
| 390 // In order to guarantee error in log below 1ulp, we compute log |
| 391 // by |
| 392 // log1p(f) = f - (hfsq - s*(hfsq+R)). |
| 393 // |
| 394 // 3. Finally, log1p(x) = k*ln2 + log1p(f). |
| 395 // = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) |
| 396 // Here ln2 is split into two floating point number: |
| 397 // ln2_hi + ln2_lo, |
| 398 // where n*ln2_hi is always exact for |n| < 2000. |
| 399 // |
| 400 // Special cases: |
| 401 // log1p(x) is NaN with signal if x < -1 (including -INF) ; |
| 402 // log1p(+INF) is +INF; log1p(-1) is -INF with signal; |
| 403 // log1p(NaN) is that NaN with no signal. |
| 404 // |
| 405 // Accuracy: |
| 406 // according to an error analysis, the error is always less than |
| 407 // 1 ulp (unit in the last place). |
| 408 // |
| 409 // Constants: |
| 410 // The hexadecimal values are the intended ones for the following |
| 411 // constants. The decimal values may be used, provided that the |
| 412 // compiler will convert from decimal to binary accurately enough |
| 413 // to produce the hexadecimal values shown. |
| 414 // |
| 415 // Note: Assuming log() return accurate answer, the following |
| 416 // algorithm can be used to compute log1p(x) to within a few ULP: |
| 417 // |
| 418 // u = 1+x; |
| 419 // if (u==1.0) return x ; else |
| 420 // return log(u)*(x/(u-1.0)); |
| 421 // |
| 422 // See HP-15C Advanced Functions Handbook, p.193. |
| 423 // |
| 424 const LN2_HI = kMath[34]; |
| 425 const LN2_LO = kMath[35]; |
| 426 const TWO54 = kMath[36]; |
| 427 const TWO_THIRD = kMath[37]; |
| 428 macro KLOGP1(x) |
| 429 (kMath[38+x]) |
| 430 endmacro |
| 431 |
| 432 function MathLog1p(x) { |
| 433 x = x * 1; // Convert to number. |
| 434 var hx = %_DoubleHi(x); |
| 435 var ax = hx & 0x7fffffff; |
| 436 var k = 1; |
| 437 var f = x; |
| 438 var hu = 1; |
| 439 var c = 0; |
| 440 var u = x; |
| 441 |
| 442 if (hx < 0x3fda827a) { |
| 443 // x < 0.41422 |
| 444 if (ax >= 0x3ff00000) { // |x| >= 1 |
| 445 if (x === -1) { |
| 446 return -INFINITY; // log1p(-1) = -inf |
| 447 } else { |
| 448 return NAN; // log1p(x<-1) = NaN |
| 449 } |
| 450 } else if (ax < 0x3c900000) { |
| 451 // For |x| < 2^-54 we can return x. |
| 452 return x; |
| 453 } else if (ax < 0x3e200000) { |
| 454 // For |x| < 2^-29 we can use a simple two-term Taylor series. |
| 455 return x - x * x * 0.5; |
| 456 } |
| 457 |
| 458 if ((hx > 0) || (hx <= -0x402D413D)) { // (int) 0xbfd2bec3 = -0x402d413d |
| 459 // -.2929 < x < 0.41422 |
| 460 k = 0; |
| 461 } |
| 462 } |
| 463 |
| 464 // Handle Infinity and NAN |
| 465 if (hx >= 0x7ff00000) return x; |
| 466 |
| 467 if (k !== 0) { |
| 468 if (hx < 0x43400000) { |
| 469 // x < 2^53 |
| 470 u = 1 + x; |
| 471 hu = %_DoubleHi(u); |
| 472 k = (hu >> 20) - 1023; |
| 473 c = (k > 0) ? 1 - (u - x) : x - (u - 1); |
| 474 c = c / u; |
| 475 } else { |
| 476 hu = %_DoubleHi(u); |
| 477 k = (hu >> 20) - 1023; |
| 478 } |
| 479 hu = hu & 0xfffff; |
| 480 if (hu < 0x6a09e) { |
| 481 u = %_ConstructDouble(hu | 0x3ff00000, %_DoubleLo(u)); // Normalize u. |
| 482 } else { |
| 483 ++k; |
| 484 u = %_ConstructDouble(hu | 0x3fe00000, %_DoubleLo(u)); // Normalize u/2. |
| 485 hu = (0x00100000 - hu) >> 2; |
| 486 } |
| 487 f = u - 1; |
| 488 } |
| 489 |
| 490 var hfsq = 0.5 * f * f; |
| 491 if (hu === 0) { |
| 492 // |f| < 2^-20; |
| 493 if (f === 0) { |
| 494 if (k === 0) { |
| 495 return 0.0; |
| 496 } else { |
| 497 return k * LN2_HI + (c + k * LN2_LO); |
| 498 } |
| 499 } |
| 500 var R = hfsq * (1 - TWO_THIRD * f); |
| 501 if (k === 0) { |
| 502 return f - R; |
| 503 } else { |
| 504 return k * LN2_HI - ((R - (k * LN2_LO + c)) - f); |
| 505 } |
| 506 } |
| 507 |
| 508 var s = f / (2 + f); |
| 509 var z = s * s; |
| 510 var R = z * (KLOGP1(0) + z * (KLOGP1(1) + z * |
| 511 (KLOGP1(2) + z * (KLOGP1(3) + z * |
| 512 (KLOGP1(4) + z * (KLOGP1(5) + z * KLOGP1(6))))))); |
| 513 if (k === 0) { |
| 514 return f - (hfsq - s * (hfsq + R)); |
| 515 } else { |
| 516 return k * LN2_HI - ((hfsq - (s * (hfsq + R) + (k * LN2_LO + c))) - f); |
| 517 } |
| 518 } |
OLD | NEW |