math: extensive log*.c cleanup
authorSzabolcs Nagy <nsz@port70.net>
Mon, 28 Oct 2013 01:16:14 +0000 (01:16 +0000)
committerSzabolcs Nagy <nsz@port70.net>
Mon, 28 Oct 2013 01:16:14 +0000 (01:16 +0000)
The log, log2 and log10 functions share a lot of code and to a lesser
extent log1p too. A small part of the code was kept separately in
__log1p.h, but since it did not capture much of the common code and
it was inlined anyway, it did not solve the issue properly. Now the
log functions have significant code duplication, which may be resolved
later, until then they need to be modified together.

logl, log10l, log2l, log1pl:
* Fix the sign when the return value should be -inf.
* Remove the volatile hack from log10l (seems unnecessary)

log1p, log1pf:
* Change the handling of small inputs: only |x|<2^-53 is special
  (then it is enough to return x with the usual subnormal handling)
  this fixes the sign of log1p(0) in downward rounding.
* Do not handle the k==0 case specially (other than skipping the
  elaborate argument reduction)
* Do not handle 1+x close to power-of-two specially (this code was
  used rarely, did not give much speed up and the precision wasn't
  better than the general)
* Fix the correction term formula (c=1-(u-x) was used incorrectly
  when x<1 but (double)(x+1)==2, this was not a critical issue)
* Use the exact same method for calculating log(1+f) as in log
  (except in log1p the c correction term is added to the result).

log, logf, log10, log10f, log2, log2f:
* Use double_t and float_t consistently.
* Now the first part of log10 and log2 is identical to log (until the
  return statement, hopefully this makes maintainence easier).
* Most special case formulas were removed (close to power-of-two and
  k==0 cases), they increase the code size without providing precision
  or performance benefits (and obfuscate the code).
  Only x==1 is handled specially so in downward rounding mode the
  sign of zero is correct (the general formula happens to give -0).
* For x==0 instead of -1/0.0 or -two54/0.0, return -1/(x*x) to force
  raising the exception at runtime.
* Arg reduction code is changed (slightly simplified)
* The thresholds for arg reduction to [sqrt(2)/2,sqrt(2)] are now
  consistently the [0x3fe6a09e00000000,0x3ff6a09dffffffff] and the
  [0x3f3504f3,0x3fb504f2] intervals for double and float reductions
  respectively (the exact threshold values are not critical)
* Remove the obsolete comment for the FLT_EVAL_METHOD!=0 case in log2f
  (The same code is used for all eval methods now, on i386 slightly
  simpler code could be used, but we have asm there anyway)

all:
* Fix signed int arithmetics (using unsigned for bitmanipulation)
* Fix various comments

14 files changed:
src/math/__log1p.h [deleted file]
src/math/__log1pf.h [deleted file]
src/math/log.c
src/math/log10.c
src/math/log10f.c
src/math/log10l.c
src/math/log1p.c
src/math/log1pf.c
src/math/log1pl.c
src/math/log2.c
src/math/log2f.c
src/math/log2l.c
src/math/logf.c
src/math/logl.c

diff --git a/src/math/__log1p.h b/src/math/__log1p.h
deleted file mode 100644 (file)
index 5718711..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/k_log.h */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * 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.
- * ====================================================
- */
-/*
- * __log1p(f):
- * Return log(1+f) - f for 1+f in ~[sqrt(2)/2, sqrt(2)].
- *
- * The following describes the overall strategy for computing
- * logarithms in base e.  The argument reduction and adding the final
- * term of the polynomial are done by the caller for increased accuracy
- * when different bases are used.
- *
- * Method :
- *   1. Argument Reduction: find k and f such that
- *                      x = 2^k * (1+f),
- *         where  sqrt(2)/2 < 1+f < sqrt(2) .
- *
- *   2. Approximation of log(1+f).
- *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
- *               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
- *               = 2s + s*R
- *      We use a special Reme algorithm on [0,0.1716] to generate
- *      a polynomial of degree 14 to approximate R The maximum error
- *      of this polynomial approximation is bounded by 2**-58.45. In
- *      other words,
- *                      2      4      6      8      10      12      14
- *          R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
- *      (the values of Lg1 to Lg7 are listed in the program)
- *      and
- *          |      2          14          |     -58.45
- *          | Lg1*s +...+Lg7*s    -  R(z) | <= 2
- *          |                             |
- *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
- *      In order to guarantee error in log below 1ulp, we compute log
- *      by
- *              log(1+f) = f - s*(f - R)        (if f is not too large)
- *              log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy)
- *
- *      3. Finally,  log(x) = k*ln2 + log(1+f).
- *                          = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
- *         Here ln2 is split into two floating point number:
- *                      ln2_hi + ln2_lo,
- *         where n*ln2_hi is always exact for |n| < 2000.
- *
- * Special cases:
- *      log(x) is NaN with signal if x < 0 (including -INF) ;
- *      log(+INF) is +INF; log(0) is -INF with signal;
- *      log(NaN) is that NaN with no signal.
- *
- * Accuracy:
- *      according to an error analysis, the error is always less than
- *      1 ulp (unit in the last place).
- *
- * Constants:
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-static const double
-Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
-Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
-Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
-Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
-Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
-Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
-Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
-
-/*
- * We always inline __log1p(), since doing so produces a
- * substantial performance improvement (~40% on amd64).
- */
-static inline double __log1p(double f)
-{
-       double_t hfsq,s,z,R,w,t1,t2;
-
-       s = f/(2.0+f);
-       z = s*s;
-       w = z*z;
-       t1= w*(Lg2+w*(Lg4+w*Lg6));
-       t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
-       R = t2+t1;
-       hfsq = 0.5*f*f;
-       return s*(hfsq+R);
-}
diff --git a/src/math/__log1pf.h b/src/math/__log1pf.h
deleted file mode 100644 (file)
index f2fbef2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/k_logf.h */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * See comments in __log1p.h.
- */
-
-/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
-static const float
-Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
-Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
-Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
-Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
-
-static inline float __log1pf(float f)
-{
-       float_t hfsq,s,z,R,w,t1,t2;
-
-       s = f/(2.0f + f);
-       z = s*s;
-       w = z*z;
-       t1 = w*(Lg2+w*Lg4);
-       t2 = z*(Lg1+w*Lg3);
-       R = t2+t1;
-       hfsq = 0.5f * f * f;
-       return s*(hfsq+R);
-}
index 98051205f80ec607d416a645a1d77d63cb0eebc8..e61e113d41af91f86d4482a979c84966be66fe33 100644 (file)
@@ -10,7 +10,7 @@
  * ====================================================
  */
 /* log(x)
- * Return the logrithm of x
+ * Return the logarithm of x
  *
  * Method :
  *   1. Argument Reduction: find k and f such that
  * to produce the hexadecimal values shown.
  */
 
-#include "libm.h"
+#include <math.h>
+#include <stdint.h>
 
 static const double
 ln2_hi = 6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */
 ln2_lo = 1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */
-two54  = 1.80143985094819840000e+16,  /* 43500000 00000000 */
 Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
 Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
 Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
@@ -76,63 +76,43 @@ Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
 
 double log(double x)
 {
-       double hfsq,f,s,z,R,w,t1,t2,dk;
-       int32_t k,hx,i,j;
-       uint32_t lx;
-
-       EXTRACT_WORDS(hx, lx, x);
+       union {double f; uint64_t i;} u = {x};
+       double_t hfsq,f,s,z,R,w,t1,t2,dk;
+       uint32_t hx;
+       int k;
 
+       hx = u.i>>32;
        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 */
+       if (hx < 0x00100000 || hx>>31) {
+               if (u.i<<1 == 0)
+                       return -1/(x*x);  /* log(+-0)=-inf */
+               if (hx>>31)
+                       return (x-x)/0.0; /* log(-#) = NaN */
+               /* subnormal number, scale x up */
                k -= 54;
-               x *= two54;
-               GET_HIGH_WORD(hx,x);
-       }
-       if (hx >= 0x7ff00000)
-               return x+x;
-       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;
+               x *= 0x1p54;
+               u.f = x;
+               hx = u.i>>32;
+       } else if (hx >= 0x7ff00000) {
+               return x;
+       } else if (hx == 0x3ff00000 && u.i<<32 == 0)
+               return 0;
+
+       /* reduce x into [sqrt(2)/2, sqrt(2)] */
+       hx += 0x3ff00000 - 0x3fe6a09e;
+       k += (int)(hx>>20) - 0x3ff;
+       hx = (hx&0x000fffff) + 0x3fe6a09e;
+       u.i = (uint64_t)hx<<32 | (u.i&0xffffffff);
+       x = u.f;
+
        f = x - 1.0;
-       if ((0x000fffff&(2+hx)) < 3) {  /* -2**-20 <= f < 2**-20 */
-               if (f == 0.0) {
-                       if (k == 0) {
-                               return 0.0;
-                       }
-                       dk = (double)k;
-                       return dk*ln2_hi + dk*ln2_lo;
-               }
-               R = f*f*(0.5-0.33333333333333333*f);
-               if (k == 0)
-                       return f - R;
-               dk = (double)k;
-               return dk*ln2_hi - ((R-dk*ln2_lo)-f);
-       }
+       hfsq = 0.5*f*f;
        s = f/(2.0+f);
-       dk = (double)k;
        z = s*s;
-       i = hx - 0x6147a;
        w = z*z;
-       j = 0x6b851 - hx;
        t1 = w*(Lg2+w*(Lg4+w*Lg6));
        t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
-       i |= j;
        R = t2 + t1;
-       if (i > 0) {
-               hfsq = 0.5*f*f;
-               if (k == 0)
-                       return f - (hfsq-s*(hfsq+R));
-               return dk*ln2_hi - ((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
-       } else {
-               if (k == 0)
-                       return f - s*(f-R);
-               return dk*ln2_hi - ((s*(f-R)-dk*ln2_lo)-f);
-       }
+       dk = k;
+       return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi;
 }
index ed65d9bee739c75fa5cf631397c840877dec6e0d..81026876b223d4f56d6c2542b18898d6105aa34d 100644 (file)
  * ====================================================
  */
 /*
- * Return the base 10 logarithm of x.  See e_log.c and k_log.h for most
- * comments.
+ * Return the base 10 logarithm of x.  See log.c for most comments.
  *
- *    log10(x) = (f - 0.5*f*f + k_log1p(f)) / ln10 + k * log10(2)
- * in not-quite-routine extra precision.
+ * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2
+ * as in log.c, then combine and scale in extra precision:
+ *    log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2)
  */
 
-#include "libm.h"
-#include "__log1p.h"
+#include <math.h>
+#include <stdint.h>
 
 static const double
-two54     = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
 ivln10hi  = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */
 ivln10lo  = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */
 log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
-log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
 
 double log10(double x)
 {
-       double f,hfsq,hi,lo,r,val_hi,val_lo,w,y,y2;
-       int32_t i,k,hx;
-       uint32_t lx;
-
-       EXTRACT_WORDS(hx, lx, x);
+       union {double f; uint64_t i;} u = {x};
+       double_t hfsq,f,s,z,R,w,t1,t2,dk,y,hi,lo,val_hi,val_lo;
+       uint32_t hx;
+       int k;
 
+       hx = u.i>>32;
        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 */
+       if (hx < 0x00100000 || hx>>31) {
+               if (u.i<<1 == 0)
+                       return -1/(x*x);  /* log(+-0)=-inf */
+               if (hx>>31)
+                       return (x-x)/0.0; /* log(-#) = NaN */
+               /* subnormal number, scale x up */
                k -= 54;
-               x *= two54;
-               GET_HIGH_WORD(hx, x);
-       }
-       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;
+               x *= 0x1p54;
+               u.f = x;
+               hx = u.i>>32;
+       } else if (hx >= 0x7ff00000) {
+               return x;
+       } else if (hx == 0x3ff00000 && u.i<<32 == 0)
+               return 0;
+
+       /* reduce x into [sqrt(2)/2, sqrt(2)] */
+       hx += 0x3ff00000 - 0x3fe6a09e;
+       k += (int)(hx>>20) - 0x3ff;
+       hx = (hx&0x000fffff) + 0x3fe6a09e;
+       u.i = (uint64_t)hx<<32 | (u.i&0xffffffff);
+       x = u.f;
+
        f = x - 1.0;
        hfsq = 0.5*f*f;
-       r = __log1p(f);
+       s = f/(2.0+f);
+       z = s*s;
+       w = z*z;
+       t1 = w*(Lg2+w*(Lg4+w*Lg6));
+       t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+       R = t2 + t1;
 
        /* See log2.c for details. */
+       /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */
        hi = f - hfsq;
-       SET_LOW_WORD(hi, 0);
-       lo = (f - hi) - hfsq + r;
+       u.f = hi;
+       u.i &= (uint64_t)-1<<32;
+       hi = u.f;
+       lo = f - hi - hfsq + s*(hfsq+R);
+
+       /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */
        val_hi = hi*ivln10hi;
-       y2 = y*log10_2hi;
-       val_lo = y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi;
+       dk = k;
+       y = dk*log10_2hi;
+       val_lo = dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi;
 
        /*
-        * Extra precision in for adding y*log10_2hi is not strictly needed
+        * Extra precision in for adding y is not strictly needed
         * since there is no very large cancellation near x = sqrt(2) or
         * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs
         * with some parallelism and it reduces the error for many args.
         */
-       w = y2 + val_hi;
-       val_lo += (y2 - w) + val_hi;
+       w = y + val_hi;
+       val_lo += (y - w) + val_hi;
        val_hi = w;
 
        return val_lo + val_hi;
index e10749b5bbeedb9f482f82961c58bcba7daf010a..9ca2f017da666e2a4da75df66f1ab846eb0537e9 100644 (file)
  * See comments in log10.c.
  */
 
-#include "libm.h"
-#include "__log1pf.h"
+#include <math.h>
+#include <stdint.h>
 
 static const float
-two25     =  3.3554432000e+07, /* 0x4c000000 */
 ivln10hi  =  4.3432617188e-01, /* 0x3ede6000 */
 ivln10lo  = -3.1689971365e-05, /* 0xb804ead9 */
 log10_2hi =  3.0102920532e-01, /* 0x3e9a2080 */
-log10_2lo =  7.9034151668e-07; /* 0x355427db */
+log10_2lo =  7.9034151668e-07, /* 0x355427db */
+/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
+Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
+Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
+Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
+Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
 
 float log10f(float x)
 {
-       float f,hfsq,hi,lo,r,y;
-       int32_t i,k,hx;
-
-       GET_FLOAT_WORD(hx, x);
+       union {float f; uint32_t i;} u = {x};
+       float_t hfsq,f,s,z,R,w,t1,t2,dk,hi,lo;
+       uint32_t ix;
+       int k;
 
+       ix = u.i;
        k = 0;
-       if (hx < 0x00800000) {  /* x < 2**-126  */
-               if ((hx&0x7fffffff) == 0)
-                       return -two25/0.0f;  /* log(+-0)=-inf */
-               if (hx < 0)
-                       return (x-x)/0.0f;   /* log(-#) = NaN */
+       if (ix < 0x00800000 || ix>>31) {  /* x < 2**-126  */
+               if (ix<<1 == 0)
+                       return -1/(x*x);  /* log(+-0)=-inf */
+               if (ix>>31)
+                       return (x-x)/0.0f; /* log(-#) = NaN */
                /* subnormal number, scale up x */
                k -= 25;
-               x *= two25;
-               GET_FLOAT_WORD(hx, x);
-       }
-       if (hx >= 0x7f800000)
-               return x+x;
-       if (hx == 0x3f800000)
-               return 0.0f;  /* log(1) = +0 */
-       k += (hx>>23) - 127;
-       hx &= 0x007fffff;
-       i = (hx+(0x4afb0d))&0x800000;
-       SET_FLOAT_WORD(x, hx|(i^0x3f800000));  /* normalize x or x/2 */
-       k += i>>23;
-       y = (float)k;
+               x *= 0x1p25f;
+               u.f = x;
+               ix = u.i;
+       } else if (ix >= 0x7f800000) {
+               return x;
+       } else if (ix == 0x3f800000)
+               return 0;
+
+       /* reduce x into [sqrt(2)/2, sqrt(2)] */
+       ix += 0x3f800000 - 0x3f3504f3;
+       k += (int)(ix>>23) - 0x7f;
+       ix = (ix&0x007fffff) + 0x3f3504f3;
+       u.i = ix;
+       x = u.f;
+
        f = x - 1.0f;
-       hfsq = 0.5f * f * f;
-       r = __log1pf(f);
+       s = f/(2.0f + f);
+       z = s*s;
+       w = z*z;
+       t1= w*(Lg2+w*Lg4);
+       t2= z*(Lg1+w*Lg3);
+       R = t2 + t1;
+       hfsq = 0.5f*f*f;
 
-// FIXME
-//      /* See log2f.c and log2.c for details. */
-//      if (sizeof(float_t) > sizeof(float))
-//              return (r - hfsq + f) * ((float_t)ivln10lo + ivln10hi) +
-//                  y * ((float_t)log10_2lo + log10_2hi);
        hi = f - hfsq;
-       GET_FLOAT_WORD(hx, hi);
-       SET_FLOAT_WORD(hi, hx&0xfffff000);
-       lo = (f - hi) - hfsq + r;
-       return y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi +
-               hi*ivln10hi + y*log10_2hi;
+       u.f = hi;
+       u.i &= 0xfffff000;
+       hi = u.f;
+       lo = f - hi - hfsq + s*(hfsq+R);
+       dk = k;
+       return dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + dk*log10_2hi;
 }
index f0eeeafb4a733a916d45d2b485886c35d5843973..c7aacf909a45156d1f60513f60ee237ad36e8272 100644 (file)
@@ -117,16 +117,15 @@ static const long double S[4] = {
 
 long double log10l(long double x)
 {
-       long double y;
-       volatile long double z;
+       long double y, z;
        int e;
 
        if (isnan(x))
                return x;
        if(x <= 0.0) {
                if(x == 0.0)
-                       return -1.0 / (x - x);
-               return (x - x) / (x - x);
+                       return -1.0 / (x*x);
+               return (x - x) / 0.0;
        }
        if (x == INFINITY)
                return INFINITY;
index a71ac42367dda0fed4ff396656f06fcdd05e4155..0097134940378136f861708e6b952a8d67f76b3c 100644 (file)
@@ -10,6 +10,7 @@
  * ====================================================
  */
 /* double log1p(double x)
+ * Return the natural logarithm of 1+x.
  *
  * Method :
  *   1. Argument Reduction: find k and f such that
  *      and add back the correction term c/u.
  *      (Note: when x > 2**53, one can simply return log(x))
  *
- *   2. Approximation of log1p(f).
- *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
- *               = 2s + 2/3 s**3 + 2/5 s**5 + .....,
- *               = 2s + s*R
- *      We use a special Reme algorithm on [0,0.1716] to generate
- *      a polynomial of degree 14 to approximate R The maximum error
- *      of this polynomial approximation is bounded by 2**-58.45. In
- *      other words,
- *                      2      4      6      8      10      12      14
- *          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
- *      (the values of Lp1 to Lp7 are listed in the program)
- *      and
- *          |      2          14          |     -58.45
- *          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
- *          |                             |
- *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
- *      In order to guarantee error in log below 1ulp, we compute log
- *      by
- *              log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *   2. Approximation of log(1+f): See log.c
  *
- *      3. Finally, log1p(x) = k*ln2 + log1p(f).
- *                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
- *         Here ln2 is split into two floating point number:
- *                      ln2_hi + ln2_lo,
- *         where n*ln2_hi is always exact for |n| < 2000.
+ *   3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c
  *
  * Special cases:
  *      log1p(x) is NaN with signal if x < -1 (including -INF) ;
 static const double
 ln2_hi = 6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */
 ln2_lo = 1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */
-two54  = 1.80143985094819840000e+16,  /* 43500000 00000000 */
-Lp1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
-Lp2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
-Lp3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
-Lp4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
-Lp5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
-Lp6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
-Lp7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
 
 double log1p(double x)
 {
-       double hfsq,f,c,s,z,R,u;
-       int32_t k,hx,hu,ax;
-
-       GET_HIGH_WORD(hx, x);
-       ax = hx & 0x7fffffff;
+       union {double f; uint64_t i;} u = {x};
+       double_t hfsq,f,c,s,z,R,w,t1,t2,dk;
+       uint32_t hx,hu;
+       int k;
 
+       hx = u.i>>32;
        k = 1;
-       if (hx < 0x3FDA827A) {  /* 1+x < sqrt(2)+ */
-               if (ax >= 0x3ff00000) {  /* x <= -1.0 */
-                       if (x == -1.0)
-                               return -two54/0.0; /* log1p(-1)=+inf */
-                       return (x-x)/(x-x);         /* log1p(x<-1)=NaN */
+       if (hx < 0x3fda827a || hx>>31) {  /* 1+x < sqrt(2)+ */
+               if (hx >= 0xbff00000) {  /* x <= -1.0 */
+                       if (x == -1)
+                               return x/0.0; /* log1p(-1) = -inf */
+                       return (x-x)/0.0;     /* log1p(x<-1) = NaN */
                }
-               if (ax < 0x3e200000) {   /* |x| < 2**-29 */
-                       /* if 0x1p-1022 <= |x| < 0x1p-54, avoid raising underflow */
-                       if (ax < 0x3c900000 && ax >= 0x00100000)
-                               return x;
-#if FLT_EVAL_METHOD != 0
-                       FORCE_EVAL((float)x);
-#endif
-                       return x - x*x*0.5;
+               if (hx<<1 < 0x3ca00000<<1) {  /* |x| < 2**-53 */
+                       /* underflow if subnormal */
+                       if ((hx&0x7ff00000) == 0)
+                               FORCE_EVAL((float)x);
+                       return x;
                }
-               if (hx > 0 || hx <= (int32_t)0xbfd2bec4) {  /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
+               if (hx <= 0xbfd2bec4) {  /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
                        k = 0;
+                       c = 0;
                        f = x;
-                       hu = 1;
                }
-       }
-       if (hx >= 0x7ff00000)
-               return x+x;
-       if (k != 0) {
-               if (hx < 0x43400000) {
-                       u = 1 + x;
-                       GET_HIGH_WORD(hu, u);
-                       k = (hu>>20) - 1023;
-                       c = k > 0 ? 1.0-(u-x) : x-(u-1.0); /* correction term */
-                       c /= u;
-               } else {
-                       u = x;
-                       GET_HIGH_WORD(hu,u);
-                       k = (hu>>20) - 1023;
+       } else if (hx >= 0x7ff00000)
+               return x;
+       if (k) {
+               u.f = 1 + x;
+               hu = u.i>>32;
+               hu += 0x3ff00000 - 0x3fe6a09e;
+               k = (int)(hu>>20) - 0x3ff;
+               /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
+               if (k < 54) {
+                       c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
+                       c /= u.f;
+               } else
                        c = 0;
-               }
-               hu &= 0x000fffff;
-               /*
-                * The approximation to sqrt(2) used in thresholds is not
-                * critical.  However, the ones used above must give less
-                * strict bounds than the one here so that the k==0 case is
-                * never reached from here, since here we have committed to
-                * using the correction term but don't use it if k==0.
-                */
-               if (hu < 0x6a09e) {  /* u ~< sqrt(2) */
-                       SET_HIGH_WORD(u, hu|0x3ff00000); /* normalize u */
-               } else {
-                       k += 1;
-                       SET_HIGH_WORD(u, hu|0x3fe00000); /* normalize u/2 */
-                       hu = (0x00100000-hu)>>2;
-               }
-               f = u - 1.0;
+               /* reduce u into [sqrt(2)/2, sqrt(2)] */
+               hu = (hu&0x000fffff) + 0x3fe6a09e;
+               u.i = (uint64_t)hu<<32 | (u.i&0xffffffff);
+               f = u.f - 1;
        }
        hfsq = 0.5*f*f;
-       if (hu == 0) {   /* |f| < 2**-20 */
-               if (f == 0.0) {
-                       if(k == 0)
-                               return 0.0;
-                       c += k*ln2_lo;
-                       return k*ln2_hi + c;
-               }
-               R = hfsq*(1.0 - 0.66666666666666666*f);
-               if (k == 0)
-                       return f - R;
-               return k*ln2_hi - ((R-(k*ln2_lo+c))-f);
-       }
        s = f/(2.0+f);
        z = s*s;
-       R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
-       if (k == 0)
-               return f - (hfsq-s*(hfsq+R));
-       return k*ln2_hi - ((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+       w = z*z;
+       t1 = w*(Lg2+w*(Lg4+w*Lg6));
+       t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+       R = t2 + t1;
+       dk = k;
+       return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
 }
index e6940d296eac6f21c441bfcc38055da481b00dda..23985c35675842d925bbc3c1475bd419926e0fda 100644 (file)
@@ -1,7 +1,4 @@
 /* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
 /*
  * ====================================================
  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 static const float
 ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
 ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
-two25  = 3.355443200e+07,  /* 0x4c000000 */
-Lp1 = 6.6666668653e-01, /* 3F2AAAAB */
-Lp2 = 4.0000000596e-01, /* 3ECCCCCD */
-Lp3 = 2.8571429849e-01, /* 3E924925 */
-Lp4 = 2.2222198546e-01, /* 3E638E29 */
-Lp5 = 1.8183572590e-01, /* 3E3A3325 */
-Lp6 = 1.5313838422e-01, /* 3E1CD04F */
-Lp7 = 1.4798198640e-01; /* 3E178897 */
+/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
+Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
+Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
+Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
+Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
 
 float log1pf(float x)
 {
-       float hfsq,f,c,s,z,R,u;
-       int32_t k,hx,hu,ax;
-
-       GET_FLOAT_WORD(hx, x);
-       ax = hx & 0x7fffffff;
+       union {float f; uint32_t i;} u = {x};
+       float_t hfsq,f,c,s,z,R,w,t1,t2,dk;
+       uint32_t ix,iu;
+       int k;
 
+       ix = u.i;
        k = 1;
-       if (hx < 0x3ed413d0) {  /* 1+x < sqrt(2)+  */
-               if (ax >= 0x3f800000) {  /* x <= -1.0 */
-                       if (x == -1.0f)
-                               return -two25/0.0f; /* log1p(-1)=+inf */
-                       return (x-x)/(x-x);         /* log1p(x<-1)=NaN */
+       if (ix < 0x3ed413d0 || ix>>31) {  /* 1+x < sqrt(2)+  */
+               if (ix >= 0xbf800000) {  /* x <= -1.0 */
+                       if (x == -1)
+                               return x/0.0f; /* log1p(-1)=+inf */
+                       return (x-x)/0.0f;     /* log1p(x<-1)=NaN */
                }
-               if (ax < 0x38000000) {   /* |x| < 2**-15 */
-                       /* if 0x1p-126 <= |x| < 0x1p-24, avoid raising underflow */
-                       if (ax < 0x33800000 && ax >= 0x00800000)
-                               return x;
-#if FLT_EVAL_METHOD != 0
-                       FORCE_EVAL(x*x);
-#endif
-                       return x - x*x*0.5f;
+               if (ix<<1 < 0x33800000<<1) {   /* |x| < 2**-24 */
+                       /* underflow if subnormal */
+                       if ((ix&0x7f800000) == 0)
+                               FORCE_EVAL(x*x);
+                       return x;
                }
-               if (hx > 0 || hx <= (int32_t)0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
+               if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
                        k = 0;
+                       c = 0;
                        f = x;
-                       hu = 1;
                }
-       }
-       if (hx >= 0x7f800000)
-               return x+x;
-       if (k != 0) {
-               if (hx < 0x5a000000) {
-                       u = 1 + x;
-                       GET_FLOAT_WORD(hu, u);
-                       k = (hu>>23) - 127;
-                       /* correction term */
-                       c = k > 0 ? 1.0f-(u-x) : x-(u-1.0f);
-                       c /= u;
-               } else {
-                       u = x;
-                       GET_FLOAT_WORD(hu,u);
-                       k = (hu>>23) - 127;
+       } else if (ix >= 0x7f800000)
+               return x;
+       if (k) {
+               u.f = 1 + x;
+               iu = u.i;
+               iu += 0x3f800000 - 0x3f3504f3;
+               k = (int)(iu>>23) - 0x7f;
+               /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
+               if (k < 25) {
+                       c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
+                       c /= u.f;
+               } else
                        c = 0;
-               }
-               hu &= 0x007fffff;
-               /*
-                * The approximation to sqrt(2) used in thresholds is not
-                * critical.  However, the ones used above must give less
-                * strict bounds than the one here so that the k==0 case is
-                * never reached from here, since here we have committed to
-                * using the correction term but don't use it if k==0.
-                */
-               if (hu < 0x3504f4) {  /* u < sqrt(2) */
-                       SET_FLOAT_WORD(u, hu|0x3f800000);  /* normalize u */
-               } else {
-                       k += 1;
-                       SET_FLOAT_WORD(u, hu|0x3f000000);  /* normalize u/2 */
-                       hu = (0x00800000-hu)>>2;
-               }
-               f = u - 1.0f;
-       }
-       hfsq = 0.5f * f * f;
-       if (hu == 0) {  /* |f| < 2**-20 */
-               if (f == 0.0f) {
-                       if (k == 0)
-                               return 0.0f;
-                       c += k*ln2_lo;
-                       return k*ln2_hi+c;
-               }
-               R = hfsq*(1.0f - 0.66666666666666666f * f);
-               if (k == 0)
-                       return f - R;
-               return k*ln2_hi - ((R-(k*ln2_lo+c))-f);
+               /* reduce u into [sqrt(2)/2, sqrt(2)] */
+               iu = (iu&0x007fffff) + 0x3f3504f3;
+               u.i = iu;
+               f = u.f - 1;
        }
        s = f/(2.0f + f);
        z = s*s;
-       R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
-       if (k == 0)
-               return f - (hfsq-s*(hfsq+R));
-       return k*ln2_hi - ((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+       w = z*z;
+       t1= w*(Lg2+w*Lg4);
+       t2= z*(Lg1+w*Lg3);
+       R = t2 + t1;
+       hfsq = 0.5f*f*f;
+       dk = k;
+       return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
 }
index edb48df1cd9c0ea5bdfb937f377654304651e4c4..37da46d23914b311f3ae75ea64ec29fed817fb10 100644 (file)
@@ -118,7 +118,7 @@ long double log1pl(long double xm1)
        /* Test for domain errors.  */
        if (x <= 0.0) {
                if (x == 0.0)
-                       return -1/x; /* -inf with divbyzero */
+                       return -1/(x*x); /* -inf with divbyzero */
                return 0/0.0f; /* nan with invalid */
        }
 
index 1974215d658168dcc9794ce6260d434802cae82d..0aafad4b86c1cd3bf7b69090534aa1f5a05fda36 100644 (file)
  * ====================================================
  */
 /*
- * Return the base 2 logarithm of x.  See log.c and __log1p.h for most
- * comments.
+ * Return the base 2 logarithm of x.  See log.c 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.
+ * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2
+ * as in log.c, then combine and scale in extra precision:
+ *    log2(x) = (f - f*f/2 + r)/log(2) + k
  */
 
-#include "libm.h"
-#include "__log1p.h"
+#include <math.h>
+#include <stdint.h>
 
 static const double
-two54   = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
 ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */
-ivln2lo = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */
+ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
 
 double log2(double x)
 {
-       double f,hfsq,hi,lo,r,val_hi,val_lo,w,y;
-       int32_t i,k,hx;
-       uint32_t lx;
-
-       EXTRACT_WORDS(hx, lx, x);
+       union {double f; uint64_t i;} u = {x};
+       double_t hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo;
+       uint32_t hx;
+       int k;
 
+       hx = u.i>>32;
        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 */
+       if (hx < 0x00100000 || hx>>31) {
+               if (u.i<<1 == 0)
+                       return -1/(x*x);  /* log(+-0)=-inf */
+               if (hx>>31)
+                       return (x-x)/0.0; /* log(-#) = NaN */
+               /* subnormal number, scale x up */
                k -= 54;
-               x *= two54;
-               GET_HIGH_WORD(hx, x);
-       }
-       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;
+               x *= 0x1p54;
+               u.f = x;
+               hx = u.i>>32;
+       } else if (hx >= 0x7ff00000) {
+               return x;
+       } else if (hx == 0x3ff00000 && u.i<<32 == 0)
+               return 0;
+
+       /* reduce x into [sqrt(2)/2, sqrt(2)] */
+       hx += 0x3ff00000 - 0x3fe6a09e;
+       k += (int)(hx>>20) - 0x3ff;
+       hx = (hx&0x000fffff) + 0x3fe6a09e;
+       u.i = (uint64_t)hx<<32 | (u.i&0xffffffff);
+       x = u.f;
+
        f = x - 1.0;
        hfsq = 0.5*f*f;
-       r = __log1p(f);
+       s = f/(2.0+f);
+       z = s*s;
+       w = z*z;
+       t1 = w*(Lg2+w*(Lg4+w*Lg6));
+       t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+       R = t2 + t1;
 
        /*
         * f-hfsq must (for args near 1) be evaluated in extra precision
@@ -90,13 +101,19 @@ double log2(double x)
         * The multi-precision calculations for the multiplications are
         * routine.
         */
+
+       /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */
        hi = f - hfsq;
-       SET_LOW_WORD(hi, 0);
-       lo = (f - hi) - hfsq + r;
+       u.f = hi;
+       u.i &= (uint64_t)-1<<32;
+       hi = u.f;
+       lo = f - hi - hfsq + s*(hfsq+R);
+
        val_hi = hi*ivln2hi;
        val_lo = (lo+hi)*ivln2lo + lo*ivln2hi;
 
        /* spadd(val_hi, val_lo, y), except for not using double_t: */
+       y = k;
        w = y + val_hi;
        val_lo += (y - w) + val_hi;
        val_hi = w;
index e0d6a9e4b2f28697f9e0efc05273ad19de29108d..b3e305fe2a629f13a6967444d1d875289b430a0f 100644 (file)
  * See comments in log2.c.
  */
 
-#include "libm.h"
-#include "__log1pf.h"
+#include <math.h>
+#include <stdint.h>
 
 static const float
-two25   =  3.3554432000e+07, /* 0x4c000000 */
 ivln2hi =  1.4428710938e+00, /* 0x3fb8b000 */
-ivln2lo = -1.7605285393e-04; /* 0xb9389ad4 */
+ivln2lo = -1.7605285393e-04, /* 0xb9389ad4 */
+/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
+Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
+Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
+Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
+Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
 
 float log2f(float x)
 {
-       float f,hfsq,hi,lo,r,y;
-       int32_t i,k,hx;
-
-       GET_FLOAT_WORD(hx, x);
+       union {float f; uint32_t i;} u = {x};
+       float_t hfsq,f,s,z,R,w,t1,t2,hi,lo;
+       uint32_t ix;
+       int k;
 
+       ix = u.i;
        k = 0;
-       if (hx < 0x00800000) {  /* x < 2**-126  */
-               if ((hx&0x7fffffff) == 0)
-                       return -two25/0.0f;  /* log(+-0)=-inf */
-               if (hx < 0)
-                       return (x-x)/0.0f;   /* log(-#) = NaN */
+       if (ix < 0x00800000 || ix>>31) {  /* x < 2**-126  */
+               if (ix<<1 == 0)
+                       return -1/(x*x);  /* log(+-0)=-inf */
+               if (ix>>31)
+                       return (x-x)/0.0f; /* log(-#) = NaN */
                /* subnormal number, scale up x */
                k -= 25;
-               x *= two25;
-               GET_FLOAT_WORD(hx, x);
-       }
-       if (hx >= 0x7f800000)
-               return x+x;
-       if (hx == 0x3f800000)
-               return 0.0f;  /* log(1) = +0 */
-       k += (hx>>23) - 127;
-       hx &= 0x007fffff;
-       i = (hx+(0x4afb0d))&0x800000;
-       SET_FLOAT_WORD(x, hx|(i^0x3f800000));  /* normalize x or x/2 */
-       k += i>>23;
-       y = (float)k;
-       f = x - 1.0f;
-       hfsq = 0.5f * f * f;
-       r = __log1pf(f);
+               x *= 0x1p25f;
+               u.f = x;
+               ix = u.i;
+       } else if (ix >= 0x7f800000) {
+               return x;
+       } else if (ix == 0x3f800000)
+               return 0;
 
-       /*
-        * We no longer need to avoid falling into the multi-precision
-        * calculations due to compiler bugs breaking Dekker's theorem.
-        * Keep avoiding this as an optimization.  See log2.c for more
-        * details (some details are here only because the optimization
-        * is not yet available in double precision).
-        *
-        * Another compiler bug turned up.  With gcc on i386,
-        * (ivln2lo + ivln2hi) would be evaluated in float precision
-        * despite runtime evaluations using double precision.  So we
-        * must cast one of its terms to float_t.  This makes the whole
-        * expression have type float_t, so return is forced to waste
-        * time clobbering its extra precision.
-        */
-// FIXME
-//      if (sizeof(float_t) > sizeof(float))
-//              return (r - hfsq + f) * ((float_t)ivln2lo + ivln2hi) + y;
+       /* reduce x into [sqrt(2)/2, sqrt(2)] */
+       ix += 0x3f800000 - 0x3f3504f3;
+       k += (int)(ix>>23) - 0x7f;
+       ix = (ix&0x007fffff) + 0x3f3504f3;
+       u.i = ix;
+       x = u.f;
+
+       f = x - 1.0f;
+       s = f/(2.0f + f);
+       z = s*s;
+       w = z*z;
+       t1= w*(Lg2+w*Lg4);
+       t2= z*(Lg1+w*Lg3);
+       R = t2 + t1;
+       hfsq = 0.5f*f*f;
 
        hi = f - hfsq;
-       GET_FLOAT_WORD(hx,hi);
-       SET_FLOAT_WORD(hi,hx&0xfffff000);
-       lo = (f - hi) - hfsq + r;
-       return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + y;
+       u.f = hi;
+       u.i &= 0xfffff000;
+       hi = u.f;
+       lo = f - hi - hfsq + s*(hfsq+R);
+       return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + k;
 }
index 345b395daf6eafd340122c0c35b96ca6f6c4ee5b..d00531d5976e26796ab126d616fb3057ce280029 100644 (file)
@@ -117,7 +117,7 @@ long double log2l(long double x)
                return x;
        if (x <= 0.0) {
                if (x == 0.0)
-                       return -1/(x+0); /* -inf with divbyzero */
+                       return -1/(x*x); /* -inf with divbyzero */
                return 0/0.0f; /* nan with invalid */
        }
 
index c7f7dbe6fee1dab14c9a845cfc4dcb9738a1257a..52230a1bd4dd6776fc55163729763766b589010e 100644 (file)
  * ====================================================
  */
 
-#include "libm.h"
+#include <math.h>
+#include <stdint.h>
 
 static const float
 ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
 ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
-two25  = 3.355443200e+07,  /* 0x4c000000 */
 /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
 Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
 Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
@@ -27,61 +27,43 @@ Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
 
 float logf(float x)
 {
-       float hfsq,f,s,z,R,w,t1,t2,dk;
-       int32_t k,ix,i,j;
-
-       GET_FLOAT_WORD(ix, x);
+       union {float f; uint32_t i;} u = {x};
+       float_t hfsq,f,s,z,R,w,t1,t2,dk;
+       uint32_t ix;
+       int k;
 
+       ix = u.i;
        k = 0;
-       if (ix < 0x00800000) {  /* x < 2**-126  */
-               if ((ix & 0x7fffffff) == 0)
-                       return -two25/0.0f;  /* log(+-0)=-inf */
-               if (ix < 0)
-                       return (x-x)/0.0f;   /* log(-#) = NaN */
+       if (ix < 0x00800000 || ix>>31) {  /* x < 2**-126  */
+               if (ix<<1 == 0)
+                       return -1/(x*x);  /* log(+-0)=-inf */
+               if (ix>>31)
+                       return (x-x)/0.0f; /* log(-#) = NaN */
                /* subnormal number, scale up x */
                k -= 25;
-               x *= two25;
-               GET_FLOAT_WORD(ix, x);
-       }
-       if (ix >= 0x7f800000)
-               return x+x;
-       k += (ix>>23) - 127;
-       ix &= 0x007fffff;
-       i = (ix + (0x95f64<<3)) & 0x800000;
-       SET_FLOAT_WORD(x, ix|(i^0x3f800000));  /* normalize x or x/2 */
-       k += i>>23;
+               x *= 0x1p25f;
+               u.f = x;
+               ix = u.i;
+       } else if (ix >= 0x7f800000) {
+               return x;
+       } else if (ix == 0x3f800000)
+               return 0;
+
+       /* reduce x into [sqrt(2)/2, sqrt(2)] */
+       ix += 0x3f800000 - 0x3f3504f3;
+       k += (int)(ix>>23) - 0x7f;
+       ix = (ix&0x007fffff) + 0x3f3504f3;
+       u.i = ix;
+       x = u.f;
+
        f = x - 1.0f;
-       if ((0x007fffff & (0x8000 + ix)) < 0xc000) {  /* -2**-9 <= f < 2**-9 */
-               if (f == 0.0f) {
-                       if (k == 0)
-                               return 0.0f;
-                       dk = (float)k;
-                       return dk*ln2_hi + dk*ln2_lo;
-               }
-               R = f*f*(0.5f - 0.33333333333333333f*f);
-               if (k == 0)
-                       return f-R;
-               dk = (float)k;
-               return dk*ln2_hi - ((R-dk*ln2_lo)-f);
-       }
        s = f/(2.0f + f);
-       dk = (float)k;
        z = s*s;
-       i = ix-(0x6147a<<3);
        w = z*z;
-       j = (0x6b851<<3)-ix;
        t1= w*(Lg2+w*Lg4);
        t2= z*(Lg1+w*Lg3);
-       i |= j;
        R = t2 + t1;
-       if (i > 0) {
-               hfsq = 0.5f * f * f;
-               if (k == 0)
-                       return f - (hfsq-s*(hfsq+R));
-               return dk*ln2_hi - ((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
-       } else {
-               if (k == 0)
-                       return f - s*(f-R);
-               return dk*ln2_hi - ((s*(f-R)-dk*ln2_lo)-f);
-       }
+       hfsq = 0.5f*f*f;
+       dk = k;
+       return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi;
 }
index ef2b55156ad57f18f1b9223054440ea4e1569d5f..03c5188fd9d79389d938cff1b6900ea90fa4aaf3 100644 (file)
@@ -35,9 +35,9 @@
  *
  *     log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x).
  *
- * Otherwise, setting  z = 2(x-1)/x+1),
+ * Otherwise, setting  z = 2(x-1)/(x+1),
  *
- *     log(x) = z + z**3 P(z)/Q(z).
+ *     log(x) = log(1+z/2) - log(1-z/2) = z + z**3 P(z)/Q(z).
  *
  *
  * ACCURACY:
@@ -116,7 +116,7 @@ long double logl(long double x)
                return x;
        if (x <= 0.0) {
                if (x == 0.0)
-                       return -1/(x+0); /* -inf with divbyzero */
+                       return -1/(x*x); /* -inf with divbyzero */
                return 0/0.0f; /* nan with invalid */
        }
 
@@ -127,7 +127,7 @@ long double logl(long double x)
        x = frexpl(x, &e);
 
        /* logarithm using log(x) = z + z**3 P(z)/Q(z),
-        * where z = 2(x-1)/x+1)
+        * where z = 2(x-1)/(x+1)
         */
        if (e > 2 || e < -2) {
                if (x < SQRTH) {  /* 2(2x-1)/(2x+1) */