prevent CNAME/PTR parsing from reading data past the response end
[musl] / src / math / log2.c
index 1974215..1276ed4 100644 (file)
-/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */
 /*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ * Double-precision log2(x) function.
  *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * Return the base 2 logarithm of x.  See log.c and __log1p.h for most
- * comments.
- *
- * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel,
- * then does the combining and scaling steps
- *    log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k
- * in not-quite-routine extra precision.
+ * Copyright (c) 2018, Arm Limited.
+ * SPDX-License-Identifier: MIT
  */
 
+#include <math.h>
+#include <stdint.h>
 #include "libm.h"
-#include "__log1p.h"
+#include "log2_data.h"
 
-static const double
-two54   = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
-ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */
-ivln2lo = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */
+#define T __log2_data.tab
+#define T2 __log2_data.tab2
+#define B __log2_data.poly1
+#define A __log2_data.poly
+#define InvLn2hi __log2_data.invln2hi
+#define InvLn2lo __log2_data.invln2lo
+#define N (1 << LOG2_TABLE_BITS)
+#define OFF 0x3fe6000000000000
 
-double log2(double x)
+/* Top 16 bits of a double.  */
+static inline uint32_t top16(double x)
 {
-       double f,hfsq,hi,lo,r,val_hi,val_lo,w,y;
-       int32_t i,k,hx;
-       uint32_t lx;
+       return asuint64(x) >> 48;
+}
 
-       EXTRACT_WORDS(hx, lx, x);
+double log2(double x)
+{
+       double_t z, r, r2, r4, y, invc, logc, kd, hi, lo, t1, t2, t3, p;
+       uint64_t ix, iz, tmp;
+       uint32_t top;
+       int k, i;
 
-       k = 0;
-       if (hx < 0x00100000) {  /* x < 2**-1022  */
-               if (((hx&0x7fffffff)|lx) == 0)
-                       return -two54/0.0;  /* log(+-0)=-inf */
-               if (hx < 0)
-                       return (x-x)/0.0;   /* log(-#) = NaN */
-               /* subnormal number, scale up x */
-               k -= 54;
-               x *= two54;
-               GET_HIGH_WORD(hx, x);
+       ix = asuint64(x);
+       top = top16(x);
+#define LO asuint64(1.0 - 0x1.5b51p-5)
+#define HI asuint64(1.0 + 0x1.6ab2p-5)
+       if (predict_false(ix - LO < HI - LO)) {
+               /* Handle close to 1.0 inputs separately.  */
+               /* Fix sign of zero with downward rounding when x==1.  */
+               if (WANT_ROUNDING && predict_false(ix == asuint64(1.0)))
+                       return 0;
+               r = x - 1.0;
+#if __FP_FAST_FMA
+               hi = r * InvLn2hi;
+               lo = r * InvLn2lo + __builtin_fma(r, InvLn2hi, -hi);
+#else
+               double_t rhi, rlo;
+               rhi = asdouble(asuint64(r) & -1ULL << 32);
+               rlo = r - rhi;
+               hi = rhi * InvLn2hi;
+               lo = rlo * InvLn2hi + r * InvLn2lo;
+#endif
+               r2 = r * r; /* rounding error: 0x1p-62.  */
+               r4 = r2 * r2;
+               /* Worst-case error is less than 0.54 ULP (0.55 ULP without fma).  */
+               p = r2 * (B[0] + r * B[1]);
+               y = hi + p;
+               lo += hi - y + p;
+               lo += r4 * (B[2] + r * B[3] + r2 * (B[4] + r * B[5]) +
+                           r4 * (B[6] + r * B[7] + r2 * (B[8] + r * B[9])));
+               y += lo;
+               return eval_as_double(y);
        }
-       if (hx >= 0x7ff00000)
-               return x+x;
-       if (hx == 0x3ff00000 && lx == 0)
-               return 0.0;  /* log(1) = +0 */
-       k += (hx>>20) - 1023;
-       hx &= 0x000fffff;
-       i = (hx+0x95f64) & 0x100000;
-       SET_HIGH_WORD(x, hx|(i^0x3ff00000));  /* normalize x or x/2 */
-       k += i>>20;
-       y = (double)k;
-       f = x - 1.0;
-       hfsq = 0.5*f*f;
-       r = __log1p(f);
+       if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) {
+               /* x < 0x1p-1022 or inf or nan.  */
+               if (ix * 2 == 0)
+                       return __math_divzero(1);
+               if (ix == asuint64(INFINITY)) /* log(inf) == inf.  */
+                       return x;
+               if ((top & 0x8000) || (top & 0x7ff0) == 0x7ff0)
+                       return __math_invalid(x);
+               /* x is subnormal, normalize it.  */
+               ix = asuint64(x * 0x1p52);
+               ix -= 52ULL << 52;
+       }
+
+       /* x = 2^k z; where z is in range [OFF,2*OFF) and exact.
+          The range is split into N subintervals.
+          The ith subinterval contains z and c is near its center.  */
+       tmp = ix - OFF;
+       i = (tmp >> (52 - LOG2_TABLE_BITS)) % N;
+       k = (int64_t)tmp >> 52; /* arithmetic shift */
+       iz = ix - (tmp & 0xfffULL << 52);
+       invc = T[i].invc;
+       logc = T[i].logc;
+       z = asdouble(iz);
+       kd = (double_t)k;
 
-       /*
-        * f-hfsq must (for args near 1) be evaluated in extra precision
-        * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2).
-        * This is fairly efficient since f-hfsq only depends on f, so can
-        * be evaluated in parallel with R.  Not combining hfsq with R also
-        * keeps R small (though not as small as a true `lo' term would be),
-        * so that extra precision is not needed for terms involving R.
-        *
-        * Compiler bugs involving extra precision used to break Dekker's
-        * theorem for spitting f-hfsq as hi+lo, unless double_t was used
-        * or the multi-precision calculations were avoided when double_t
-        * has extra precision.  These problems are now automatically
-        * avoided as a side effect of the optimization of combining the
-        * Dekker splitting step with the clear-low-bits step.
-        *
-        * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra
-        * precision to avoid a very large cancellation when x is very near
-        * these values.  Unlike the above cancellations, this problem is
-        * specific to base 2.  It is strange that adding +-1 is so much
-        * harder than adding +-ln2 or +-log10_2.
-        *
-        * This uses Dekker's theorem to normalize y+val_hi, so the
-        * compiler bugs are back in some configurations, sigh.  And I
-        * don't want to used double_t to avoid them, since that gives a
-        * pessimization and the support for avoiding the pessimization
-        * is not yet available.
-        *
-        * The multi-precision calculations for the multiplications are
-        * routine.
-        */
-       hi = f - hfsq;
-       SET_LOW_WORD(hi, 0);
-       lo = (f - hi) - hfsq + r;
-       val_hi = hi*ivln2hi;
-       val_lo = (lo+hi)*ivln2lo + lo*ivln2hi;
+       /* log2(x) = log2(z/c) + log2(c) + k.  */
+       /* r ~= z/c - 1, |r| < 1/(2*N).  */
+#if __FP_FAST_FMA
+       /* rounding error: 0x1p-55/N.  */
+       r = __builtin_fma(z, invc, -1.0);
+       t1 = r * InvLn2hi;
+       t2 = r * InvLn2lo + __builtin_fma(r, InvLn2hi, -t1);
+#else
+       double_t rhi, rlo;
+       /* rounding error: 0x1p-55/N + 0x1p-65.  */
+       r = (z - T2[i].chi - T2[i].clo) * invc;
+       rhi = asdouble(asuint64(r) & -1ULL << 32);
+       rlo = r - rhi;
+       t1 = rhi * InvLn2hi;
+       t2 = rlo * InvLn2hi + r * InvLn2lo;
+#endif
 
-       /* spadd(val_hi, val_lo, y), except for not using double_t: */
-       w = y + val_hi;
-       val_lo += (y - w) + val_hi;
-       val_hi = w;
+       /* hi + lo = r/ln2 + log2(c) + k.  */
+       t3 = kd + logc;
+       hi = t3 + t1;
+       lo = t3 - hi + t1 + t2;
 
-       return val_lo + val_hi;
+       /* log2(r+1) = r/ln2 + r^2*poly(r).  */
+       /* Evaluation is optimized assuming superscalar pipelined execution.  */
+       r2 = r * r; /* rounding error: 0x1p-54/N^2.  */
+       r4 = r2 * r2;
+       /* Worst-case error if |y| > 0x1p-4: 0.547 ULP (0.550 ULP without fma).
+          ~ 0.5 + 2/N/ln2 + abs-poly-error*0x1p56 ULP (+ 0.003 ULP without fma).  */
+       p = A[0] + r * A[1] + r2 * (A[2] + r * A[3]) + r4 * (A[4] + r * A[5]);
+       y = lo + r2 * p + hi;
+       return eval_as_double(y);
 }