Author: kargl
Date: Sun Aug 31 21:38:03 2014
New Revision: 270893
URL: http://svnweb.freebsd.org/changeset/base/270893

Log:
  Compute sin(pi*x) without actually doing the pi*x multiplication.
  sin_pi(x) is only called for x < 0 and |x| < 2**(p-1) where p is
  the precision of x.  The new argument reduction is an optimization
  compared to the old code, and it removes a chunk of dead code.
  Accuracy tests in the intervals (-21,-20), (-20,-19), ... (-1,0)
  show no differences between the old and new code.
  
  Obtained from:        bde

Modified:
  head/lib/msun/src/e_lgamma_r.c
  head/lib/msun/src/e_lgammaf_r.c

Modified: head/lib/msun/src/e_lgamma_r.c
==============================================================================
--- head/lib/msun/src/e_lgamma_r.c      Sun Aug 31 21:18:23 2014        
(r270892)
+++ head/lib/msun/src/e_lgamma_r.c      Sun Aug 31 21:38:03 2014        
(r270893)
@@ -156,37 +156,35 @@ w6  = -1.63092934096575273989e-03; /* 0x
 
 static const double zero=  0.00000000000000000000e+00;
 
-       static double sin_pi(double x)
+/*
+ * Compute sin(pi*x) without actually doing the pi*x multiplication.
+ * sin_pi(x) is only called for x < 0 and |x| < 2**(p-1) where p is
+ * the precision of x.
+ */
+static double
+sin_pi(double x)
 {
+       volatile double vz;
        double y,z;
-       int n,ix;
+       int n;
 
-       GET_HIGH_WORD(ix,x);
-       ix &= 0x7fffffff;
+       y = -x;
 
-       if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
-       y = -x;         /* x is assume negative */
+       vz = y+0x1p52;                  /* depend on 0 <= y < 0x1p52 */
+        z = vz-0x1p52;                 /* rint(y) for the above range */
+       if (z == y)
+           return (zero);
+
+       vz = y+0x1p50;
+       GET_LOW_WORD(n,vz);             /* bits for rounded y (units 0.25) */
+       z = vz-0x1p50;                  /* y rounded to a multiple of 0.25 */
+       if (z > y) {
+           z -= 0.25;                  /* adjust to round down */
+           n--;
+       }
+       n &= 7;                         /* octant of y mod 2 */
+       y = y - z + n * 0.25;           /* y mod 2 */
 
-    /*
-     * argument reduction, make sure inexact flag not raised if input
-     * is an integer
-     */
-       z = floor(y);
-       if(z!=y) {                              /* inexact anyway */
-           y  *= 0.5;
-           y   = 2.0*(y - floor(y));           /* y = |x| mod 2.0 */
-           n   = (int) (y*4.0);
-       } else {
-            if(ix>=0x43400000) {
-                y = zero; n = 0;                 /* y must be even */
-            } else {
-                if(ix<0x43300000) z = y+two52; /* exact */
-               GET_LOW_WORD(n,z);
-               n &= 1;
-                y  = n;
-                n<<= 2;
-            }
-        }
        switch (n) {
            case 0:   y =  __kernel_sin(pi*y,zero,0); break;
            case 1:   

Modified: head/lib/msun/src/e_lgammaf_r.c
==============================================================================
--- head/lib/msun/src/e_lgammaf_r.c     Sun Aug 31 21:18:23 2014        
(r270892)
+++ head/lib/msun/src/e_lgammaf_r.c     Sun Aug 31 21:38:03 2014        
(r270893)
@@ -89,37 +89,35 @@ w6  = -1.6309292987e-03; /* 0xbad5c4e8 *
 
 static const float zero=  0.0000000000e+00;
 
-       static float sin_pif(float x)
+/*
+ * Compute sin(pi*x) without actually doing the pi*x multiplication.
+ * sin_pi(x) is only called for x < 0 and |x| < 2**(p-1) where p is
+ * the precision of x.
+ */
+static float
+sin_pi(float x)
 {
+       volatile float vz;
        float y,z;
-       int n,ix;
+       int n;
 
-       GET_FLOAT_WORD(ix,x);
-       ix &= 0x7fffffff;
+       y = -x;
 
-       if(ix<0x3e800000) return __kernel_sindf(pi*x);
-       y = -x;         /* x is assume negative */
+       vz = y+0x1p23F;                 /* depend on 0 <= y < 0x1p23 */
+       z = vz-0x1p23F;                 /* rintf(y) for the above range */
+       if (z == y)
+           return (zero);
+
+       vz = y+0x1p21F;
+       GET_FLOAT_WORD(n,vz);           /* bits for rounded y (units 0.25) */
+       z = vz-0x1p21F;                 /* y rounded to a multiple of 0.25 */
+       if (z > y) {
+           z -= 0.25F;                 /* adjust to round down */
+           n--;
+       }
+       n &= 7;                         /* octant of y mod 2 */
+       y = y - z + n * 0.25F;          /* y mod 2 */
 
-    /*
-     * argument reduction, make sure inexact flag not raised if input
-     * is an integer
-     */
-       z = floorf(y);
-       if(z!=y) {                              /* inexact anyway */
-           y  *= (float)0.5;
-           y   = (float)2.0*(y - floorf(y));   /* y = |x| mod 2.0 */
-           n   = (int) (y*(float)4.0);
-       } else {
-            if(ix>=0x4b800000) {
-                y = zero; n = 0;                 /* y must be even */
-            } else {
-                if(ix<0x4b000000) z = y+two23; /* exact */
-               GET_FLOAT_WORD(n,z);
-               n &= 1;
-                y  = n;
-                n<<= 2;
-            }
-        }
        switch (n) {
            case 0:   y =  __kernel_sindf(pi*y); break;
            case 1:
@@ -157,7 +155,7 @@ __ieee754_lgammaf_r(float x, int *signga
        if(hx<0) {
            if(ix>=0x4b000000)  /* |x|>=2**23, must be -integer */
                return one/zero;
-           t = sin_pif(x);
+           t = sin_pi(x);
            if(t==zero) return one/zero; /* -integer */
            nadj = __ieee754_logf(pi/fabsf(t*x));
            if(t<zero) *signgamp = -1;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to