Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Side by Side Diff: src/third_party/fdlibm/fdlibm.js

Issue 786823003: Implement Math.log2 via ported extract from fdlibm. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: addressed comments Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698