Chromium Code Reviews| 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 |