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 // ==================================================== |
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 | 16 // The following is a straightforward translation of fdlibm routines |
17 // by Raymond Toy (rtoy@google.com). | 17 // by Raymond Toy (rtoy@google.com). |
18 | 18 |
19 // Double constants that do not have empty lower 32 bits are found in fdlibm.cc | 19 // Double constants that do not have empty lower 32 bits are found in fdlibm.cc |
20 // and exposed through kMath as typed array. We assume the compiler to convert | 20 // and exposed through kMath as typed array. We assume the compiler to convert |
21 // from decimal to binary accurately enough to produce the intended values. | 21 // from decimal to binary accurately enough to produce the intended values. |
22 // kMath is initialized to a Float64Array during genesis and not writable. | 22 // kMath is initialized to a Float64Array during genesis and not writable. |
23 | |
24 "use strict"; | |
25 | |
23 var kMath; | 26 var kMath; |
24 | 27 |
25 const INVPIO2 = kMath[0]; | 28 const INVPIO2 = kMath[0]; |
26 const PIO2_1 = kMath[1]; | 29 const PIO2_1 = kMath[1]; |
27 const PIO2_1T = kMath[2]; | 30 const PIO2_1T = kMath[2]; |
28 const PIO2_2 = kMath[3]; | 31 const PIO2_2 = kMath[3]; |
29 const PIO2_2T = kMath[4]; | 32 const PIO2_2T = kMath[4]; |
30 const PIO2_3 = kMath[5]; | 33 const PIO2_3 = kMath[5]; |
31 const PIO2_3T = kMath[6]; | 34 const PIO2_3T = kMath[6]; |
32 const PIO4 = kMath[32]; | 35 const PIO4 = kMath[32]; |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
417 // algorithm can be used to compute log1p(x) to within a few ULP: | 420 // algorithm can be used to compute log1p(x) to within a few ULP: |
418 // | 421 // |
419 // u = 1+x; | 422 // u = 1+x; |
420 // if (u==1.0) return x ; else | 423 // if (u==1.0) return x ; else |
421 // return log(u)*(x/(u-1.0)); | 424 // return log(u)*(x/(u-1.0)); |
422 // | 425 // |
423 // See HP-15C Advanced Functions Handbook, p.193. | 426 // See HP-15C Advanced Functions Handbook, p.193. |
424 // | 427 // |
425 const LN2_HI = kMath[34]; | 428 const LN2_HI = kMath[34]; |
426 const LN2_LO = kMath[35]; | 429 const LN2_LO = kMath[35]; |
427 const TWO54 = kMath[36]; | 430 const TWO_THIRD = kMath[36]; |
428 const TWO_THIRD = kMath[37]; | |
429 macro KLOG1P(x) | 431 macro KLOG1P(x) |
430 (kMath[38+x]) | 432 (kMath[37+x]) |
431 endmacro | 433 endmacro |
434 // 2^54 | |
435 const TWO54 = 18014398509481984; | |
432 | 436 |
433 function MathLog1p(x) { | 437 function MathLog1p(x) { |
434 x = x * 1; // Convert to number. | 438 x = x * 1; // Convert to number. |
435 var hx = %_DoubleHi(x); | 439 var hx = %_DoubleHi(x); |
436 var ax = hx & 0x7fffffff; | 440 var ax = hx & 0x7fffffff; |
437 var k = 1; | 441 var k = 1; |
438 var f = x; | 442 var f = x; |
439 var hu = 1; | 443 var hu = 1; |
440 var c = 0; | 444 var c = 0; |
441 var u = x; | 445 var u = x; |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 // for finite argument, only expm1(0)=0 is exact. | 604 // for finite argument, only expm1(0)=0 is exact. |
601 // | 605 // |
602 // Accuracy: | 606 // Accuracy: |
603 // according to an error analysis, the error is always less than | 607 // according to an error analysis, the error is always less than |
604 // 1 ulp (unit in the last place). | 608 // 1 ulp (unit in the last place). |
605 // | 609 // |
606 // Misc. info. | 610 // Misc. info. |
607 // For IEEE double | 611 // For IEEE double |
608 // if x > 7.09782712893383973096e+02 then expm1(x) overflow | 612 // if x > 7.09782712893383973096e+02 then expm1(x) overflow |
609 // | 613 // |
610 const KEXPM1_OVERFLOW = kMath[45]; | 614 const KEXPM1_OVERFLOW = kMath[44]; |
Raymond Toy
2014/12/10 17:15:53
I think it would be nice to have KEXPM1_TABLE_OFFS
| |
611 const INVLN2 = kMath[46]; | 615 const INVLN2 = kMath[45]; |
612 macro KEXPM1(x) | 616 macro KEXPM1(x) |
613 (kMath[47+x]) | 617 (kMath[46+x]) |
614 endmacro | 618 endmacro |
615 | 619 |
616 function MathExpm1(x) { | 620 function MathExpm1(x) { |
617 x = x * 1; // Convert to number. | 621 x = x * 1; // Convert to number. |
618 var y; | 622 var y; |
619 var hi; | 623 var hi; |
620 var lo; | 624 var lo; |
621 var k; | 625 var k; |
622 var t; | 626 var t; |
623 var c; | 627 var c; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
723 // 2 | 727 // 2 |
724 // | 728 // |
725 // 22 <= x <= lnovft : sinh(x) := exp(x)/2 | 729 // 22 <= x <= lnovft : sinh(x) := exp(x)/2 |
726 // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) | 730 // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) |
727 // ln2ovft < x : sinh(x) := x*shuge (overflow) | 731 // ln2ovft < x : sinh(x) := x*shuge (overflow) |
728 // | 732 // |
729 // Special cases: | 733 // Special cases: |
730 // sinh(x) is |x| if x is +Infinity, -Infinity, or NaN. | 734 // sinh(x) is |x| if x is +Infinity, -Infinity, or NaN. |
731 // only sinh(0)=0 is exact for finite x. | 735 // only sinh(0)=0 is exact for finite x. |
732 // | 736 // |
733 const KSINH_OVERFLOW = kMath[52]; | 737 const KSINH_OVERFLOW = kMath[51]; |
734 const TWO_M28 = 3.725290298461914e-9; // 2^-28, empty lower half | 738 const TWO_M28 = 3.725290298461914e-9; // 2^-28, empty lower half |
735 const LOG_MAXD = 709.7822265625; // 0x40862e42 00000000, empty lower half | 739 const LOG_MAXD = 709.7822265625; // 0x40862e42 00000000, empty lower half |
736 | 740 |
737 function MathSinh(x) { | 741 function MathSinh(x) { |
738 x = x * 1; // Convert to number. | 742 x = x * 1; // Convert to number. |
739 var h = (x < 0) ? -0.5 : 0.5; | 743 var h = (x < 0) ? -0.5 : 0.5; |
740 // |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1)) | 744 // |x| in [0, 22]. return sign(x)*0.5*(E+E/(E+1)) |
741 var ax = MathAbs(x); | 745 var ax = MathAbs(x); |
742 if (ax < 22) { | 746 if (ax < 22) { |
743 // For |x| < 2^-28, sinh(x) = x | 747 // For |x| < 2^-28, sinh(x) = x |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
775 // ln2/2 <= x <= 22 : cosh(x) := ------------------- | 779 // ln2/2 <= x <= 22 : cosh(x) := ------------------- |
776 // 2 | 780 // 2 |
777 // 22 <= x <= lnovft : cosh(x) := exp(x)/2 | 781 // 22 <= x <= lnovft : cosh(x) := exp(x)/2 |
778 // lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) | 782 // lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) |
779 // ln2ovft < x : cosh(x) := huge*huge (overflow) | 783 // ln2ovft < x : cosh(x) := huge*huge (overflow) |
780 // | 784 // |
781 // Special cases: | 785 // Special cases: |
782 // cosh(x) is |x| if x is +INF, -INF, or NaN. | 786 // cosh(x) is |x| if x is +INF, -INF, or NaN. |
783 // only cosh(0)=1 is exact for finite x. | 787 // only cosh(0)=1 is exact for finite x. |
784 // | 788 // |
785 const KCOSH_OVERFLOW = kMath[52]; | 789 const KCOSH_OVERFLOW = kMath[51]; |
786 | 790 |
787 function MathCosh(x) { | 791 function MathCosh(x) { |
788 x = x * 1; // Convert to number. | 792 x = x * 1; // Convert to number. |
789 var ix = %_DoubleHi(x) & 0x7fffffff; | 793 var ix = %_DoubleHi(x) & 0x7fffffff; |
790 // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|)) | 794 // |x| in [0,0.5*log2], return 1+expm1(|x|)^2/(2*exp(|x|)) |
791 if (ix < 0x3fd62e43) { | 795 if (ix < 0x3fd62e43) { |
792 var t = MathExpm1(MathAbs(x)); | 796 var t = MathExpm1(MathAbs(x)); |
793 var w = 1 + t; | 797 var w = 1 + t; |
794 // For |x| < 2^-55, cosh(x) = 1 | 798 // For |x| < 2^-55, cosh(x) = 1 |
795 if (ix < 0x3c800000) return w; | 799 if (ix < 0x3c800000) return w; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
833 // [1/log(10)] rounded to 53 bits has error .198 ulps; | 837 // [1/log(10)] rounded to 53 bits has error .198 ulps; |
834 // log10 is monotonic at all binary break points. | 838 // log10 is monotonic at all binary break points. |
835 // | 839 // |
836 // Special cases: | 840 // Special cases: |
837 // log10(x) is NaN if x < 0; | 841 // log10(x) is NaN if x < 0; |
838 // log10(+INF) is +INF; log10(0) is -INF; | 842 // log10(+INF) is +INF; log10(0) is -INF; |
839 // log10(NaN) is that NaN; | 843 // log10(NaN) is that NaN; |
840 // log10(10**N) = N for N=0,1,...,22. | 844 // log10(10**N) = N for N=0,1,...,22. |
841 // | 845 // |
842 | 846 |
843 const IVLN10 = kMath[53]; | 847 const IVLN10 = kMath[52]; |
844 const LOG10_2HI = kMath[54]; | 848 const LOG10_2HI = kMath[53]; |
845 const LOG10_2LO = kMath[55]; | 849 const LOG10_2LO = kMath[54]; |
846 | 850 |
847 function MathLog10(x) { | 851 function MathLog10(x) { |
848 x = x * 1; // Convert to number. | 852 x = x * 1; // Convert to number. |
849 var hx = %_DoubleHi(x); | 853 var hx = %_DoubleHi(x); |
850 var lx = %_DoubleLo(x); | 854 var lx = %_DoubleLo(x); |
851 var k = 0; | 855 var k = 0; |
852 | 856 |
853 if (hx < 0x00100000) { | 857 if (hx < 0x00100000) { |
854 // x < 2^-1022 | 858 // x < 2^-1022 |
855 // log10(+/- 0) = -Infinity. | 859 // log10(+/- 0) = -Infinity. |
(...skipping 12 matching lines...) Expand all Loading... | |
868 | 872 |
869 k += (hx >> 20) - 1023; | 873 k += (hx >> 20) - 1023; |
870 i = (k & 0x80000000) >> 31; | 874 i = (k & 0x80000000) >> 31; |
871 hx = (hx & 0x000fffff) | ((0x3ff - i) << 20); | 875 hx = (hx & 0x000fffff) | ((0x3ff - i) << 20); |
872 y = k + i; | 876 y = k + i; |
873 x = %_ConstructDouble(hx, lx); | 877 x = %_ConstructDouble(hx, lx); |
874 | 878 |
875 z = y * LOG10_2LO + IVLN10 * MathLog(x); | 879 z = y * LOG10_2LO + IVLN10 * MathLog(x); |
876 return z + y * LOG10_2HI; | 880 return z + y * LOG10_2HI; |
877 } | 881 } |
882 | |
883 | |
884 // ES6 draft 09-27-13, section 20.2.2.22. | |
885 // Return the base 2 logarithm of x | |
886 // | |
887 // fdlibm does not have an explicit log2 function, but fdlibm's pow | |
888 // function does implement an accurate log2 function as part of the | |
889 // pow implementation. This extracts the core parts of that as a | |
890 // separate log2 function. | |
891 | |
892 // Method: | |
893 // Compute log2(x) in two pieces: | |
894 // log2(x) = w1 + w2 | |
895 // where w1 has 53-24 = 29 bits of trailing zeroes. | |
896 | |
897 const DP_H = kMath[64]; | |
898 const DP_L = kMath[65]; | |
899 | |
900 // Polynomial coefficients for (3/2)*(log2(x) - 2*s - 2/3*s^3) | |
901 macro KLOG2(x) | |
902 (kMath[55+x]) | |
903 endmacro | |
904 | |
905 // cp = 2/(3*ln(2)). Note that cp_h + cp_l is cp, but with more accuracy. | |
906 const CP = kMath[61]; | |
907 const CP_H = kMath[62]; | |
908 const CP_L = kMath[63]; | |
909 // 2^53 | |
910 const TWO53 = 9007199254740992; | |
911 | |
912 function MathLog2(x) { | |
913 x = x * 1; // Convert to number. | |
914 var ax = MathAbs(x); | |
915 var hx = %_DoubleHi(x); | |
916 var lx = %_DoubleLo(x); | |
917 var ix = hx & 0x7fffffff; | |
918 | |
919 // Handle special cases. | |
920 // log2(+/- 0) = -Infinity | |
921 if ((ix | lx) == 0) return -INFINITY; | |
922 | |
923 // log(x) = NaN, if x < 0 | |
924 if (hx < 0) return NAN; | |
925 | |
926 // log2(Infinity) = Infinity, log2(NaN) = NaN | |
927 if (ix >= 0x7ff00000) return x; | |
928 | |
929 var n = 0; | |
930 | |
931 // Take care of subnormal number. | |
932 if (ix < 0x00100000) { | |
933 ax *= TWO53; | |
934 n -= 53; | |
935 ix = %_DoubleHi(ax); | |
936 } | |
937 | |
938 n += (ix >> 20) - 0x3ff; | |
939 var j = ix & 0x000fffff; | |
940 | |
941 // Determine interval. | |
942 ix = j | 0x3ff00000; // normalize ix. | |
943 | |
944 var bp = 1; | |
945 var dp_h = 0; | |
946 var dp_l = 0; | |
947 if (j > 0x3988e) { // |x| > sqrt(3/2) | |
948 if (j < 0xbb67a) { // |x| < sqrt(3) | |
949 bp = 1.5; | |
950 dp_h = DP_H; | |
951 dp_l = DP_L; | |
952 } else { | |
953 n += 1; | |
954 ix -= 0x00100000; | |
955 } | |
956 } | |
957 | |
958 ax = %_ConstructDouble(ix, %_DoubleLo(ax)); | |
959 | |
960 // Compute ss = s_h + s_l = (x - 1)/(x+1) or (x - 1.5)/(x + 1.5) | |
961 var u = ax - bp; | |
962 var v = 1 / (ax + bp); | |
963 var ss = u * v; | |
964 var s_h = %_ConstructDouble(%_DoubleHi(ss), 0); | |
965 | |
966 // t_h = ax + bp[k] High | |
967 var t_h = %_ConstructDouble(%_DoubleHi(ax + bp), 0) | |
968 var t_l = ax - (t_h - bp); | |
969 var s_l = v * ((u - s_h * t_h) - s_h * t_l); | |
970 | |
971 // Compute log2(ax) | |
972 var s2 = ss * ss; | |
973 var r = s2 * s2 * (KLOG2(0) + s2 * (KLOG2(1) + s2 * (KLOG2(2) + s2 * ( | |
974 KLOG2(3) + s2 * (KLOG2(4) + s2 * KLOG2(5)))))); | |
975 r += s_l * (s_h + ss); | |
976 s2 = s_h * s_h; | |
977 t_h = %_ConstructDouble(%_DoubleHi(3.0 + s2 + r), 0); | |
978 t_l = r - ((t_h - 3.0) - s2); | |
979 // u + v = ss * (1 + ...) | |
980 u = s_h * t_h; | |
981 v = s_l * t_h + t_l * ss; | |
982 | |
983 // 2 / (3 * log(2)) * (ss + ...) | |
984 p_h = %_ConstructDouble(%_DoubleHi(u + v), 0); | |
985 p_l = v - (p_h - u); | |
986 z_h = CP_H * p_h; | |
987 z_l = CP_L * p_h + p_l * CP + dp_l; | |
988 | |
989 // log2(ax) = (ss + ...) * 2 / (3 * log(2)) = n + dp_h + z_h + z_l | |
990 var t = n; | |
991 var t1 = %_ConstructDouble(%_DoubleHi(((z_h + z_l) + dp_h) + t), 0); | |
992 var t2 = z_l - (((t1 - t) - dp_h) - z_h); | |
993 | |
994 // t1 + t2 = log2(ax), sum up because we do not care about extra precision. | |
995 return t1 + t2; | |
996 } | |
OLD | NEW |