This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Fix nexttoward* and nextafter*


Hi!

Some of nextafter* and nexttoward* are buggy.
Namely, i386 style INFINITY is 0x7fff, 0x80000000, 0x0 but the code
would do very complicated check (((hx|lx)|-(hx|lx))&hx)!=0 which is non-zero
for INFINITY as well, also ldbl-96/s_nextafterl had wrong sign e.g. for
nextafterl(-0.0, INFINITY) or nextafterl(0.0, -INFINITY).

2001-06-15  Jakub Jelinek  <jakub@redhat.com>

	* math/test-misc.c (main): Add tests for nextafter and nexttoward
	with +-Inf as second argument.

	* sysdeps/generic/s_nexttowardf.c (__nexttowardf): Only check for
	NaN, not Inf.
	* sysdeps/i386/fpu/s_nextafterl.c (__nextafterl): Fix check for NaN.
	* sysdeps/i386/fpu/s_nexttoward.c: New.
	* sysdeps/i386/fpu/s_nexttowardf.c: New.
	* sysdeps/ieee754/ldbl-96/s_nexttoward.c (__nexttoward): Simplify
	check for NaN, optimize x==+-0 handling.
	* sysdeps/ieee754/ldbl-96/s_nexttowardf.c (__nexttowardf): Likewise.
	* sysdeps/ieee754/ldbl-96/s_nextafterl.c (__nextafterl): Simplify
	check for NaN, fix sign in x==+-0 case.
	* sysdeps/ia64/fpu/s_nexttoward.c: New.
	* sysdeps/ia64/fpu/s_nexttowardf.c: New.

--- libc/math/test-misc.c.jj	Sat Jun  2 20:36:01 2001
+++ libc/math/test-misc.c	Fri Jun 15 13:44:11 2001
@@ -384,6 +384,24 @@ main (void)
 		v2.ieee.negative);
 	result = 1;
       }
+
+    if (nextafterf (0.0f, INFINITY) != nextafterf (0.0f, 1.0f)
+        || nextafterf (-0.0f, INFINITY) != nextafterf (-0.0f, 1.0f)
+        || nextafterf (0.0f, -INFINITY) != nextafterf (0.0f, -1.0f)
+        || nextafterf (-0.0f, -INFINITY) != nextafterf (-0.0f, -1.0f))
+      {
+	printf ("nextafterf (+-0, +-Inf) != nextafterf (+-0, +-1)\n");
+	result = 1;
+      }
+
+    if (nexttowardf (0.0f, INFINITY) != nexttowardf (0.0f, 1.0f)
+        || nexttowardf (-0.0f, INFINITY) != nexttowardf (-0.0f, 1.0f)
+        || nexttowardf (0.0f, -INFINITY) != nexttowardf (0.0f, -1.0f)
+        || nexttowardf (-0.0f, -INFINITY) != nexttowardf (-0.0f, -1.0f))
+      {
+	printf ("nexttowardf (+-0, +-Inf) != nexttowardf (+-0, +-1)\n");
+	result = 1;
+      }
   }
 
   {
@@ -680,6 +698,24 @@ main (void)
 		v2.ieee.negative);
 	result = 1;
       }
+
+    if (nextafter (0.0, INFINITY) != nextafter (0.0, 1.0)
+        || nextafter (-0.0, INFINITY) != nextafter (-0.0, 1.0)
+        || nextafter (0.0, -INFINITY) != nextafter (0.0, -1.0)
+        || nextafter (-0.0, -INFINITY) != nextafter (-0.0, -1.0))
+      {
+	printf ("nextafter (+-0, +-Inf) != nextafter (+-0, +-1)\n");
+	result = 1;
+      }
+
+    if (nexttoward (0.0, INFINITY) != nexttoward (0.0, 1.0)
+        || nexttoward (-0.0, INFINITY) != nexttoward (-0.0, 1.0)
+        || nexttoward (0.0, -INFINITY) != nexttoward (0.0, -1.0)
+        || nexttoward (-0.0, -INFINITY) != nexttoward (-0.0, -1.0))
+      {
+	printf ("nexttoward (+-0, +-Inf) != nexttoward (+-0, +-1)\n");
+	result = 1;
+      }
   }
 
 #ifndef NO_LONG_DOUBLE
@@ -978,6 +1014,24 @@ main (void)
       {
 	printf ("0.0L down: negative differs: 1 vs %d\n",
 		v2.ieee.negative);
+	result = 1;
+      }
+
+    if (nextafterl (0.0, INFINITY) != nextafterl (0.0, 1.0)
+        || nextafterl (-0.0, INFINITY) != nextafterl (-0.0, 1.0)
+        || nextafterl (0.0, -INFINITY) != nextafterl (0.0, -1.0)
+        || nextafterl (-0.0, -INFINITY) != nextafterl (-0.0, -1.0))
+      {
+	printf ("nextafterl (+-0, +-Inf) != nextafterl (+-0, +-1)\n");
+	result = 1;
+      }
+
+    if (nexttowardl (0.0L, INFINITY) != nexttowardl (0.0L, 1.0L)
+        || nexttowardl (-0.0L, INFINITY) != nexttowardl (-0.0L, 1.0L)
+        || nexttowardl (0.0L, -INFINITY) != nexttowardl (0.0L, -1.0L)
+        || nexttowardl (-0.0L, -INFINITY) != nexttowardl (-0.0L, -1.0L))
+      {
+	printf ("nexttowardl (+-0, +-Inf) != nexttowardl (+-0, +-1)\n");
 	result = 1;
       }
   }
--- libc/sysdeps/generic/s_nexttowardf.c.jj	Tue Oct 12 17:39:31 1999
+++ libc/sysdeps/generic/s_nexttowardf.c	Fri Jun 15 13:04:26 2001
@@ -39,7 +39,7 @@
 	ix = hx&0x7fffffff;		/* |x| */
 	iy = hy&0x7fffffff;		/* |y| */
 
-	if((ix>=0x7f800000) ||				   /* x is nan */
+	if((ix>0x7f800000) ||				   /* x is nan */
 	   ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))    /* y is nan */
 	   return x+y;
 	if((long double) x==y) return y;	/* x=y, return y */
--- libc/sysdeps/i386/fpu/s_nextafterl.c.jj	Tue Jan  2 14:18:03 2001
+++ libc/sysdeps/i386/fpu/s_nextafterl.c	Fri Jun 15 13:17:43 2001
@@ -45,10 +45,10 @@ static char rcsid[] = "$NetBSD: $";
 	ix = esx&0x7fff;		/* |x| */
 	iy = esy&0x7fff;		/* |y| */
 
-	/* The additional &hx/&hy is required because Intel's extended format
-           has the normally implicit 1 explicit present.  Sigh!  */
-	if(((ix==0x7fff)&&(((hx|lx)|-(hx|lx))&hx)>>31!=0) ||   /* x is nan */
-	   ((iy==0x7fff)&&(((hy|ly)|-(hy|ly))&hy)>>31!=0))     /* y is nan */
+	/* Intel's extended format has the normally implicit 1 explicit
+	   present.  Sigh!  */
+	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 */
--- libc/sysdeps/i386/fpu/s_nexttoward.c.jj	Fri Jun 15 13:22:20 2001
+++ libc/sysdeps/i386/fpu/s_nexttoward.c	Fri Jun 15 13:23:14 2001
@@ -0,0 +1,101 @@
+/* s_nexttoward.c
+ * Special i387 version
+ * Conversion from s_nextafter.c by Ulrich Drepper, Cygnus Support,
+ * drepper@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#if defined(LIBM_SCCS) && !defined(lint)
+static char rcsid[] = "$NetBSD: $";
+#endif
+
+/* IEEE functions
+ *	nexttoward(x,y)
+ *	return the next machine floating-point number of x in the
+ *	direction toward y.
+ *   Special cases:
+ */
+
+#include "math.h"
+#include "math_private.h"
+
+#ifdef __STDC__
+	double __nexttoward(double x, long double y)
+#else
+	double __nexttoward(x,y)
+	double x;
+	long double y;
+#endif
+{
+	int32_t hx,ix,iy;
+	u_int32_t lx,hy,ly,esy;
+
+	EXTRACT_WORDS(hx,lx,x);
+	GET_LDOUBLE_WORDS(esy,hy,ly,y);
+	ix = hx&0x7fffffff;		/* |x| */
+	iy = esy&0x7fff;		/* |y| */
+
+	/* Intel's extended format has the normally implicit 1 explicit
+	   present.  Sigh!  */
+	if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
+	   ((iy>=0x7fff)&&((hy&0x7fffffff)|ly)!=0))        /* y is nan */
+	   return x+y;
+	if((long double) x==y) return y;	/* x=y, return y */
+	if((ix|lx)==0) {			/* x == 0 */
+	    double x2;
+	    INSERT_WORDS(x,(esy&0x8000)<<16,1); /* return +-minsub */
+	    x2 = x*x;
+	    if(x2==x) return x2; else return x;	/* raise underflow flag */
+	}
+	if(hx>=0) {				/* x > 0 */
+	    if (esy>=0x8000||((ix>>20)&0x7ff)>iy-0x3c00
+		|| (((ix>>20)&0x7ff)==iy-0x3c00
+		    && (((hx<<11)|(lx>>21))>(hy&0x7fffffff)
+			|| (((hx<<11)|(lx>>21))==(hy&0x7fffffff)
+			    && (lx<<11)>ly)))) {	/* x > y, x -= ulp */
+		if(lx==0) hx -= 1;
+		lx -= 1;
+	    } else {				/* x < y, x += ulp */
+		lx += 1;
+		if(lx==0) hx += 1;
+	    }
+	} else {				/* x < 0 */
+	    if (esy<0x8000||((ix>>20)&0x7ff)>iy-0x3c00
+		|| (((ix>>20)&0x7ff)==iy-0x3c00
+		    && (((hx<<11)|(lx>>21))>(hy&0x7fffffff)
+			|| (((hx<<11)|(lx>>21))==(hy&0x7fffffff)
+			    && (lx<<11)>ly))))	{/* x < y, x -= ulp */
+		if(lx==0) hx -= 1;
+		lx -= 1;
+	    } else {				/* x > y, x += ulp */
+		lx += 1;
+		if(lx==0) hx += 1;
+	    }
+	}
+	hy = hx&0x7ff00000;
+	if(hy>=0x7ff00000) return x+x;	/* overflow  */
+	if(hy<0x00100000) {		/* underflow */
+	    double x2 = x*x;
+	    if(x2!=x) {		/* raise underflow flag */
+	        INSERT_WORDS(x2,hx,lx);
+		return x2;
+	    }
+	}
+	INSERT_WORDS(x,hx,lx);
+	return x;
+}
+weak_alias (__nexttoward, nexttoward)
+#ifdef NO_LONG_DOUBLE
+strong_alias (__nexttoward, __nexttowardl)
+weak_alias (__nexttoward, nexttowardl)
+#endif
--- libc/sysdeps/i386/fpu/s_nexttowardf.c.jj	Fri Jun 15 13:25:44 2001
+++ libc/sysdeps/i386/fpu/s_nexttowardf.c	Fri Jun 15 13:27:31 2001
@@ -0,0 +1,81 @@
+/* s_nexttowardf.c -- float version of s_nextafter.c.
+ * Special i387 version.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * 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.
+ * ====================================================
+ */
+
+#if defined(LIBM_SCCS) && !defined(lint)
+static char rcsid[] = "$NetBSD: $";
+#endif
+
+#include "math.h"
+#include "math_private.h"
+
+#ifdef __STDC__
+	float __nexttowardf(float x, long double y)
+#else
+	float __nexttowardf(x,y)
+	float x;
+	long double y;
+#endif
+{
+	int32_t hx,ix,iy;
+	u_int32_t hy,ly,esy;
+
+	GET_FLOAT_WORD(hx,x);
+	GET_LDOUBLE_WORDS(esy,hy,ly,y);
+	ix = hx&0x7fffffff;		/* |x| */
+	iy = esy&0x7fff;		/* |y| */
+
+	/* Intel's extended format has the normally implicit 1 explicit
+	   present.  Sigh!  */
+	if((ix>0x7f800000) ||			/* x is nan */
+	   (iy>=0x7fff&&(((hy&0x7fffffff)|ly)!=0))) /* y is nan */
+	   return x+y;
+	if((long double) x==y) return y;	/* x=y, return y */
+	if(ix==0) {				/* x == 0 */
+	    float x2;
+	    SET_FLOAT_WORD(x,((esy&0x8000)<<16)|1);/* return +-minsub*/
+	    x2 = x*x;
+	    if(x2==x) return x2; else return x;	/* raise underflow flag */
+	}
+	if(hx>=0) {				/* x > 0 */
+	    if(esy>=0x8000||((ix>>23)&0xff)>iy-0x3f80
+	       || (((ix>>23)&0xff)==iy-0x3f80
+		   && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x > y, x -= ulp */
+		hx -= 1;
+	    } else {				/* x < y, x += ulp */
+		hx += 1;
+	    }
+	} else {				/* x < 0 */
+	    if(esy<0x8000||((ix>>23)&0xff)>iy-0x3f80
+	       || (((ix>>23)&0xff)==iy-0x3f80
+		   && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x < y, x -= ulp */
+		hx -= 1;
+	    } else {				/* x > y, x += ulp */
+		hx += 1;
+	    }
+	}
+	hy = hx&0x7f800000;
+	if(hy>=0x7f800000) return x+x;	/* overflow  */
+	if(hy<0x00800000) {		/* underflow */
+	    float x2 = x*x;
+	    if(x2!=x) {		/* raise underflow flag */
+	        SET_FLOAT_WORD(x2,hx);
+		return x2;
+	    }
+	}
+	SET_FLOAT_WORD(x,hx);
+	return x;
+}
+weak_alias (__nexttowardf, nexttowardf)
--- libc/sysdeps/ieee754/ldbl-96/s_nexttoward.c.jj	Thu Nov  2 08:52:19 2000
+++ libc/sysdeps/ieee754/ldbl-96/s_nexttoward.c	Fri Jun 15 13:28:40 2001
@@ -45,12 +45,12 @@ static char rcsid[] = "$NetBSD: $";
 	iy = esy&0x7fff;		/* |y| */
 
 	if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
-	   ((iy>=0x7fff)&&((hy|ly)|-(hy|ly))!=0))           /* y is nan */
+	   ((iy>=0x7fff)&&(hy|ly)!=0))        /* y is nan */
 	   return x+y;
 	if((long double) x==y) return y;	/* x=y, return y */
 	if((ix|lx)==0) {			/* x == 0 */
 	    double x2;
-	    INSERT_WORDS(x,esy&0x8000?0x80000000:0,1);/* return +-minsub */
+	    INSERT_WORDS(x,(esy&0x8000)<<16,1); /* return +-minsub */
 	    x2 = x*x;
 	    if(x2==x) return x2; else return x;	/* raise underflow flag */
 	}
--- libc/sysdeps/ieee754/ldbl-96/s_nextafterl.c.jj	Wed Jul 14 02:14:34 1999
+++ libc/sysdeps/ieee754/ldbl-96/s_nextafterl.c	Fri Jun 15 13:07:08 2001
@@ -43,12 +43,12 @@ static char rcsid[] = "$NetBSD: $";
 	ix = esx&0x7fff;		/* |x| */
 	iy = esy&0x7fff;		/* |y| */
 
-	if(((ix==0x7fff)&&((hx|lx)|-(hx|lx))!=0) ||   /* x is nan */
-	   ((iy==0x7fff)&&((hy|ly)|-(hy|ly))!=0))     /* y is nan */
+	if(((ix==0x7fff)&&((hx|lx)!=0) ||   /* x is nan */
+	   ((iy==0x7fff)&&((hy|ly)!=0))     /* y is nan */
 	   return x+y;
 	if(x==y) return y;		/* x=y, return y */
 	if((ix|hx|lx)==0) {			/* x == 0 */
-	    SET_LDOUBLE_WORDS(x,esx&0x8000,0,1);/* return +-minsubnormal */
+	    SET_LDOUBLE_WORDS(x,esy&0x8000,0,1);/* return +-minsubnormal */
 	    y = x*x;
 	    if(y==x) return y; else return x;	/* raise underflow flag */
 	}
--- libc/sysdeps/ieee754/ldbl-96/s_nexttowardf.c.jj	Wed Jul 14 02:14:43 1999
+++ libc/sysdeps/ieee754/ldbl-96/s_nexttowardf.c	Fri Jun 15 13:10:52 2001
@@ -36,13 +36,13 @@ static char rcsid[] = "$NetBSD: $";
 	ix = hx&0x7fffffff;		/* |x| */
 	iy = esy&0x7fff;		/* |y| */
 
-	if((ix>0x7f800000) ||   /* x is nan */
-	   (iy>=0x7fff&&((hy|ly)|-(hy|ly))!=0))     /* y is nan */
+	if((ix>0x7f800000) ||			/* x is nan */
+	   (iy>=0x7fff&&((hy|ly)!=0)))		/* y is nan */
 	   return x+y;
 	if((long double) x==y) return y;	/* x=y, return y */
 	if(ix==0) {				/* x == 0 */
 	    float x2;
-	    SET_FLOAT_WORD(x,(esy&0x8000?0x80000000:0)|1);/* return +-minsub*/
+	    SET_FLOAT_WORD(x,((esy&0x8000)<<16)|1);/* return +-minsub*/
 	    x2 = x*x;
 	    if(x2==x) return x2; else return x;	/* raise underflow flag */
 	}
--- libc/sysdeps/ia64/fpu/s_nexttoward.c.jj	Fri Jun 15 13:24:52 2001
+++ libc/sysdeps/ia64/fpu/s_nexttoward.c	Fri Jun 15 13:24:48 2001
@@ -0,0 +1 @@
+#include <sysdeps/i386/fpu/s_nexttoward.c>
--- libc/sysdeps/ia64/fpu/s_nexttowardf.c.jj	Fri Jun 15 13:24:52 2001
+++ libc/sysdeps/ia64/fpu/s_nexttowardf.c	Fri Jun 15 13:25:23 2001
@@ -0,0 +1 @@
+#include <sysdeps/i386/fpu/s_nexttowardf.c>

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]