| 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-2004 by Sun Microsystems, Inc. All rights reserved. | 4 // Copyright (C) 1993-2004 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 // ==================================================== |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 "use strict"; | 24 "use strict"; |
| 25 | 25 |
| 26 %CheckIsBootstrapping(); | 26 %CheckIsBootstrapping(); |
| 27 | 27 |
| 28 // ------------------------------------------------------------------- | 28 // ------------------------------------------------------------------- |
| 29 // Imports | 29 // Imports |
| 30 | 30 |
| 31 var GlobalFloat64Array = global.Float64Array; | 31 var GlobalFloat64Array = global.Float64Array; |
| 32 var GlobalMath = global.Math; | 32 var GlobalMath = global.Math; |
| 33 var MathAbs; | 33 var MathAbs; |
| 34 var MathExpm1; |
| 34 var NaN = %GetRootNaN(); | 35 var NaN = %GetRootNaN(); |
| 35 var rempio2result; | 36 var rempio2result; |
| 36 | 37 |
| 37 utils.Import(function(from) { | 38 utils.Import(function(from) { |
| 38 MathAbs = from.MathAbs; | 39 MathAbs = from.MathAbs; |
| 40 MathExpm1 = from.MathExpm1; |
| 39 }); | 41 }); |
| 40 | 42 |
| 41 utils.CreateDoubleResultArray = function(global) { | 43 utils.CreateDoubleResultArray = function(global) { |
| 42 rempio2result = new GlobalFloat64Array(2); | 44 rempio2result = new GlobalFloat64Array(2); |
| 43 }; | 45 }; |
| 44 | 46 |
| 45 // ------------------------------------------------------------------- | 47 // ------------------------------------------------------------------- |
| 46 | 48 |
| 47 define INVPIO2 = 6.36619772367581382433e-01; | 49 define INVPIO2 = 6.36619772367581382433e-01; |
| 48 define PIO2_1 = 1.57079632673412561417; | 50 define PIO2_1 = 1.57079632673412561417; |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 REMPIO2(x); | 396 REMPIO2(x); |
| 395 return KernelTan(y0, y1, (n & 1) ? -1 : 1); | 397 return KernelTan(y0, y1, (n & 1) ? -1 : 1); |
| 396 } | 398 } |
| 397 | 399 |
| 398 define LN2_HI = 6.93147180369123816490e-01; | 400 define LN2_HI = 6.93147180369123816490e-01; |
| 399 define LN2_LO = 1.90821492927058770002e-10; | 401 define LN2_LO = 1.90821492927058770002e-10; |
| 400 | 402 |
| 401 // 2^54 | 403 // 2^54 |
| 402 define TWO54 = 18014398509481984; | 404 define TWO54 = 18014398509481984; |
| 403 | 405 |
| 404 // ES6 draft 09-27-13, section 20.2.2.14. | |
| 405 // Math.expm1 | |
| 406 // Returns exp(x)-1, the exponential of x minus 1. | |
| 407 // | |
| 408 // Method | |
| 409 // 1. Argument reduction: | |
| 410 // Given x, find r and integer k such that | |
| 411 // | |
| 412 // x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 | |
| 413 // | |
| 414 // Here a correction term c will be computed to compensate | |
| 415 // the error in r when rounded to a floating-point number. | |
| 416 // | |
| 417 // 2. Approximating expm1(r) by a special rational function on | |
| 418 // the interval [0,0.34658]: | |
| 419 // Since | |
| 420 // r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... | |
| 421 // we define R1(r*r) by | |
| 422 // r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) | |
| 423 // That is, | |
| 424 // R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) | |
| 425 // = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) | |
| 426 // = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... | |
| 427 // We use a special Remes algorithm on [0,0.347] to generate | |
| 428 // a polynomial of degree 5 in r*r to approximate R1. The | |
| 429 // maximum error of this polynomial approximation is bounded | |
| 430 // by 2**-61. In other words, | |
| 431 // R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 | |
| 432 // where Q1 = -1.6666666666666567384E-2, | |
| 433 // Q2 = 3.9682539681370365873E-4, | |
| 434 // Q3 = -9.9206344733435987357E-6, | |
| 435 // Q4 = 2.5051361420808517002E-7, | |
| 436 // Q5 = -6.2843505682382617102E-9; | |
| 437 // (where z=r*r, and the values of Q1 to Q5 are listed below) | |
| 438 // with error bounded by | |
| 439 // | 5 | -61 | |
| 440 // | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 | |
| 441 // | | | |
| 442 // | |
| 443 // expm1(r) = exp(r)-1 is then computed by the following | |
| 444 // specific way which minimize the accumulation rounding error: | |
| 445 // 2 3 | |
| 446 // r r [ 3 - (R1 + R1*r/2) ] | |
| 447 // expm1(r) = r + --- + --- * [--------------------] | |
| 448 // 2 2 [ 6 - r*(3 - R1*r/2) ] | |
| 449 // | |
| 450 // To compensate the error in the argument reduction, we use | |
| 451 // expm1(r+c) = expm1(r) + c + expm1(r)*c | |
| 452 // ~ expm1(r) + c + r*c | |
| 453 // Thus c+r*c will be added in as the correction terms for | |
| 454 // expm1(r+c). Now rearrange the term to avoid optimization | |
| 455 // screw up: | |
| 456 // ( 2 2 ) | |
| 457 // ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) | |
| 458 // expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) | |
| 459 // ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) | |
| 460 // ( ) | |
| 461 // | |
| 462 // = r - E | |
| 463 // 3. Scale back to obtain expm1(x): | |
| 464 // From step 1, we have | |
| 465 // expm1(x) = either 2^k*[expm1(r)+1] - 1 | |
| 466 // = or 2^k*[expm1(r) + (1-2^-k)] | |
| 467 // 4. Implementation notes: | |
| 468 // (A). To save one multiplication, we scale the coefficient Qi | |
| 469 // to Qi*2^i, and replace z by (x^2)/2. | |
| 470 // (B). To achieve maximum accuracy, we compute expm1(x) by | |
| 471 // (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) | |
| 472 // (ii) if k=0, return r-E | |
| 473 // (iii) if k=-1, return 0.5*(r-E)-0.5 | |
| 474 // (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) | |
| 475 // else return 1.0+2.0*(r-E); | |
| 476 // (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) | |
| 477 // (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else | |
| 478 // (vii) return 2^k(1-((E+2^-k)-r)) | |
| 479 // | |
| 480 // Special cases: | |
| 481 // expm1(INF) is INF, expm1(NaN) is NaN; | |
| 482 // expm1(-INF) is -1, and | |
| 483 // for finite argument, only expm1(0)=0 is exact. | |
| 484 // | |
| 485 // Accuracy: | |
| 486 // according to an error analysis, the error is always less than | |
| 487 // 1 ulp (unit in the last place). | |
| 488 // | |
| 489 // Misc. info. | |
| 490 // For IEEE double | |
| 491 // if x > 7.09782712893383973096e+02 then expm1(x) overflow | |
| 492 // | |
| 493 define KEXPM1_OVERFLOW = 7.09782712893383973096e+02; | |
| 494 define INVLN2 = 1.44269504088896338700; | |
| 495 define EXPM1_1 = -3.33333333333331316428e-02; | |
| 496 define EXPM1_2 = 1.58730158725481460165e-03; | |
| 497 define EXPM1_3 = -7.93650757867487942473e-05; | |
| 498 define EXPM1_4 = 4.00821782732936239552e-06; | |
| 499 define EXPM1_5 = -2.01099218183624371326e-07; | |
| 500 | |
| 501 function MathExpm1(x) { | |
| 502 x = x * 1; // Convert to number. | |
| 503 var y; | |
| 504 var hi; | |
| 505 var lo; | |
| 506 var k; | |
| 507 var t; | |
| 508 var c; | |
| 509 | |
| 510 var hx = %_DoubleHi(x); | |
| 511 var xsb = hx & 0x80000000; // Sign bit of x | |
| 512 var y = (xsb === 0) ? x : -x; // y = |x| | |
| 513 hx &= 0x7fffffff; // High word of |x| | |
| 514 | |
| 515 // Filter out huge and non-finite argument | |
| 516 if (hx >= 0x4043687a) { // if |x| ~=> 56 * ln2 | |
| 517 if (hx >= 0x40862e42) { // if |x| >= 709.78 | |
| 518 if (hx >= 0x7ff00000) { | |
| 519 // expm1(inf) = inf; expm1(-inf) = -1; expm1(nan) = nan; | |
| 520 return (x === -INFINITY) ? -1 : x; | |
| 521 } | |
| 522 if (x > KEXPM1_OVERFLOW) return INFINITY; // Overflow | |
| 523 } | |
| 524 if (xsb != 0) return -1; // x < -56 * ln2, return -1. | |
| 525 } | |
| 526 | |
| 527 // Argument reduction | |
| 528 if (hx > 0x3fd62e42) { // if |x| > 0.5 * ln2 | |
| 529 if (hx < 0x3ff0a2b2) { // and |x| < 1.5 * ln2 | |
| 530 if (xsb === 0) { | |
| 531 hi = x - LN2_HI; | |
| 532 lo = LN2_LO; | |
| 533 k = 1; | |
| 534 } else { | |
| 535 hi = x + LN2_HI; | |
| 536 lo = -LN2_LO; | |
| 537 k = -1; | |
| 538 } | |
| 539 } else { | |
| 540 k = (INVLN2 * x + ((xsb === 0) ? 0.5 : -0.5)) | 0; | |
| 541 t = k; | |
| 542 // t * ln2_hi is exact here. | |
| 543 hi = x - t * LN2_HI; | |
| 544 lo = t * LN2_LO; | |
| 545 } | |
| 546 x = hi - lo; | |
| 547 c = (hi - x) - lo; | |
| 548 } else if (hx < 0x3c900000) { | |
| 549 // When |x| < 2^-54, we can return x. | |
| 550 return x; | |
| 551 } else { | |
| 552 // Fall through. | |
| 553 k = 0; | |
| 554 } | |
| 555 | |
| 556 // x is now in primary range | |
| 557 var hfx = 0.5 * x; | |
| 558 var hxs = x * hfx; | |
| 559 var r1 = 1 + hxs * (EXPM1_1 + hxs * (EXPM1_2 + hxs * | |
| 560 (EXPM1_3 + hxs * (EXPM1_4 + hxs * EXPM1_5)))); | |
| 561 t = 3 - r1 * hfx; | |
| 562 var e = hxs * ((r1 - t) / (6 - x * t)); | |
| 563 if (k === 0) { // c is 0 | |
| 564 return x - (x*e - hxs); | |
| 565 } else { | |
| 566 e = (x * (e - c) - c); | |
| 567 e -= hxs; | |
| 568 if (k === -1) return 0.5 * (x - e) - 0.5; | |
| 569 if (k === 1) { | |
| 570 if (x < -0.25) return -2 * (e - (x + 0.5)); | |
| 571 return 1 + 2 * (x - e); | |
| 572 } | |
| 573 | |
| 574 if (k <= -2 || k > 56) { | |
| 575 // suffice to return exp(x) + 1 | |
| 576 y = 1 - (e - x); | |
| 577 // Add k to y's exponent | |
| 578 y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y)); | |
| 579 return y - 1; | |
| 580 } | |
| 581 if (k < 20) { | |
| 582 // t = 1 - 2^k | |
| 583 t = %_ConstructDouble(0x3ff00000 - (0x200000 >> k), 0); | |
| 584 y = t - (e - x); | |
| 585 // Add k to y's exponent | |
| 586 y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y)); | |
| 587 } else { | |
| 588 // t = 2^-k | |
| 589 t = %_ConstructDouble((0x3ff - k) << 20, 0); | |
| 590 y = x - (e + t); | |
| 591 y += 1; | |
| 592 // Add k to y's exponent | |
| 593 y = %_ConstructDouble(%_DoubleHi(y) + (k << 20), %_DoubleLo(y)); | |
| 594 } | |
| 595 } | |
| 596 return y; | |
| 597 } | |
| 598 | |
| 599 | |
| 600 // ES6 draft 09-27-13, section 20.2.2.30. | 406 // ES6 draft 09-27-13, section 20.2.2.30. |
| 601 // Math.sinh | 407 // Math.sinh |
| 602 // Method : | 408 // Method : |
| 603 // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 | 409 // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 |
| 604 // 1. Replace x by |x| (sinh(-x) = -sinh(x)). | 410 // 1. Replace x by |x| (sinh(-x) = -sinh(x)). |
| 605 // 2. | 411 // 2. |
| 606 // E + E/(E+1) | 412 // E + E/(E+1) |
| 607 // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) | 413 // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) |
| 608 // 2 | 414 // 2 |
| 609 // | 415 // |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 756 } | 562 } |
| 757 | 563 |
| 758 //------------------------------------------------------------------- | 564 //------------------------------------------------------------------- |
| 759 | 565 |
| 760 utils.InstallFunctions(GlobalMath, DONT_ENUM, [ | 566 utils.InstallFunctions(GlobalMath, DONT_ENUM, [ |
| 761 "cos", MathCos, | 567 "cos", MathCos, |
| 762 "sin", MathSin, | 568 "sin", MathSin, |
| 763 "tan", MathTan, | 569 "tan", MathTan, |
| 764 "sinh", MathSinh, | 570 "sinh", MathSinh, |
| 765 "cosh", MathCosh, | 571 "cosh", MathCosh, |
| 766 "tanh", MathTanh, | 572 "tanh", MathTanh |
| 767 "expm1", MathExpm1 | |
| 768 ]); | 573 ]); |
| 769 | 574 |
| 770 %SetForceInlineFlag(MathSin); | 575 %SetForceInlineFlag(MathSin); |
| 771 %SetForceInlineFlag(MathCos); | 576 %SetForceInlineFlag(MathCos); |
| 772 | 577 |
| 773 }) | 578 }) |
| OLD | NEW |