> Date: Mon, 2 Jun 2014 07:34:59 -0400
> From: Daniel Dickman <didick...@gmail.com>
> 
> >From the numpy test suite, I think I might have found a bug in
> nextafterl(3). The "result_ld" variable below comes back as nan on
> i386. But doing the same calculations with floats returns the expected
> values.
> 
> A test on Linux also shows the expected results for both the float and
> long double cases.

Another bug.  Intel chose an extended precision format with an
explicit integer bit, and the code doesn't handle that.  Assuming we
don't support machines with extended precision format that have an
implicit integer bit, the following diff (an adaptation of the code in
glibc) should fix things.  Not entirely happy with the fix though, so
I'm still thinking about improvements.

Index: src/ld80/s_nextafterl.c
===================================================================
RCS file: /cvs/src/lib/libm/src/ld80/s_nextafterl.c,v
retrieving revision 1.4
diff -u -p -r1.4 s_nextafterl.c
--- src/ld80/s_nextafterl.c     12 Nov 2013 21:07:28 -0000      1.4
+++ src/ld80/s_nextafterl.c     2 Jun 2014 13:21:58 -0000
@@ -32,8 +32,8 @@ nextafterl(long double x, long double y)
        ix = esx&0x7fff;                /* |x| */
        iy = esy&0x7fff;                /* |y| */
 
-       if (((ix==0x7fff)&&((hx|lx)!=0)) ||   /* x is nan */
-           ((iy==0x7fff)&&((hy|ly)!=0)))     /* y is nan */
+       if (((ix==0x7fff)&&((hx&=0x7fffffff|lx)!=0)) ||   /* x is nan */
+           ((iy==0x7fff)&&((hy&-0x7fffffff|ly)!=0)))     /* y is nan */
           return x+y;
        if(x==y) return y;              /* x=y, return y */
        if((ix|hx|lx)==0) {                     /* x == 0 */
@@ -47,31 +47,50 @@ nextafterl(long double x, long double y)
            if(ix>iy||((ix==iy) && (hx>hy||((hx==hy)&&(lx>ly))))) {
              /* x > y, x -= ulp */
                if(lx==0) {
-                   if (hx==0) esx -= 1;
-                   hx -= 1;
+                   if (hx <= 0x80000000) {
+                     if (esx == 0) {
+                       --hx;
+                     } else {
+                       esx -= 1;
+                       hx = hx - 1;
+                       if (esx > 0)
+                         hx |= 0x80000000;
+                     }
+                   } else
+                     hx -= 1;
                }
                lx -= 1;
            } else {                            /* x < y, x += ulp */
                lx += 1;
                if(lx==0) {
                    hx += 1;
-                   if (hx==0)
+                   if (hx==0 || (esx == 0 && hx == 0x80000000)) {
                        esx += 1;
+                       hx |= 0x80000000;
+                   }
                }
            }
        } else {                                /* x < 0 */
            if(esy>=0||(ix>iy||((ix==iy)&&(hx>hy||((hx==hy)&&(lx>ly)))))){
              /* x < y, x -= ulp */
                if(lx==0) {
-                   if (hx==0) esx -= 1;
-                   hx -= 1;
+                   if (hx <= 0x80000000) {
+                       esx -= 1;
+                       hx = hx - 1;
+                       if ((esx&0x7fff) > 0)
+                         hx |= 0x80000000;
+                   } else
+                     hx -= 1;
                }
                lx -= 1;
            } else {                            /* x > y, x += ulp */
                lx += 1;
                if(lx==0) {
                    hx += 1;
-                   if (hx==0) esx += 1;
+                   if (hx==0 || (esx == 0xffff8000 && hx == 0x80000000)) {
+                       esx += 1;
+                       hx |= 0x80000000;
+                   }
                }
            }
        }

Reply via email to