math: fix pow signed shift ub
[oweals/musl.git] / src / math / log2.c
1 /* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */
2 /*
3  * ====================================================
4  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5  *
6  * Developed at SunSoft, a Sun Microsystems, Inc. business.
7  * Permission to use, copy, modify, and distribute this
8  * software is freely granted, provided that this notice
9  * is preserved.
10  * ====================================================
11  */
12 /*
13  * Return the base 2 logarithm of x.  See log.c for most comments.
14  *
15  * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2
16  * as in log.c, then combine and scale in extra precision:
17  *    log2(x) = (f - f*f/2 + r)/log(2) + k
18  */
19
20 #include <math.h>
21 #include <stdint.h>
22
23 static const double
24 ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */
25 ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */
26 Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
27 Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
28 Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
29 Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
30 Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
31 Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
32 Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
33
34 double log2(double x)
35 {
36         union {double f; uint64_t i;} u = {x};
37         double_t hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo;
38         uint32_t hx;
39         int k;
40
41         hx = u.i>>32;
42         k = 0;
43         if (hx < 0x00100000 || hx>>31) {
44                 if (u.i<<1 == 0)
45                         return -1/(x*x);  /* log(+-0)=-inf */
46                 if (hx>>31)
47                         return (x-x)/0.0; /* log(-#) = NaN */
48                 /* subnormal number, scale x up */
49                 k -= 54;
50                 x *= 0x1p54;
51                 u.f = x;
52                 hx = u.i>>32;
53         } else if (hx >= 0x7ff00000) {
54                 return x;
55         } else if (hx == 0x3ff00000 && u.i<<32 == 0)
56                 return 0;
57
58         /* reduce x into [sqrt(2)/2, sqrt(2)] */
59         hx += 0x3ff00000 - 0x3fe6a09e;
60         k += (int)(hx>>20) - 0x3ff;
61         hx = (hx&0x000fffff) + 0x3fe6a09e;
62         u.i = (uint64_t)hx<<32 | (u.i&0xffffffff);
63         x = u.f;
64
65         f = x - 1.0;
66         hfsq = 0.5*f*f;
67         s = f/(2.0+f);
68         z = s*s;
69         w = z*z;
70         t1 = w*(Lg2+w*(Lg4+w*Lg6));
71         t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
72         R = t2 + t1;
73
74         /*
75          * f-hfsq must (for args near 1) be evaluated in extra precision
76          * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2).
77          * This is fairly efficient since f-hfsq only depends on f, so can
78          * be evaluated in parallel with R.  Not combining hfsq with R also
79          * keeps R small (though not as small as a true `lo' term would be),
80          * so that extra precision is not needed for terms involving R.
81          *
82          * Compiler bugs involving extra precision used to break Dekker's
83          * theorem for spitting f-hfsq as hi+lo, unless double_t was used
84          * or the multi-precision calculations were avoided when double_t
85          * has extra precision.  These problems are now automatically
86          * avoided as a side effect of the optimization of combining the
87          * Dekker splitting step with the clear-low-bits step.
88          *
89          * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra
90          * precision to avoid a very large cancellation when x is very near
91          * these values.  Unlike the above cancellations, this problem is
92          * specific to base 2.  It is strange that adding +-1 is so much
93          * harder than adding +-ln2 or +-log10_2.
94          *
95          * This uses Dekker's theorem to normalize y+val_hi, so the
96          * compiler bugs are back in some configurations, sigh.  And I
97          * don't want to used double_t to avoid them, since that gives a
98          * pessimization and the support for avoiding the pessimization
99          * is not yet available.
100          *
101          * The multi-precision calculations for the multiplications are
102          * routine.
103          */
104
105         /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */
106         hi = f - hfsq;
107         u.f = hi;
108         u.i &= (uint64_t)-1<<32;
109         hi = u.f;
110         lo = f - hi - hfsq + s*(hfsq+R);
111
112         val_hi = hi*ivln2hi;
113         val_lo = (lo+hi)*ivln2lo + lo*ivln2hi;
114
115         /* spadd(val_hi, val_lo, y), except for not using double_t: */
116         y = k;
117         w = y + val_hi;
118         val_lo += (y - w) + val_hi;
119         val_hi = w;
120
121         return val_lo + val_hi;
122 }