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 |