ce426f
commit b0abbc21034f0e5edc49023d8fda0616173faf17
ce426f
Author: Alan Modra <amodra@gmail.com>
ce426f
Date:   Wed Apr 2 13:46:19 2014 +1030
ce426f
ce426f
    Correct IBM long double nextafterl.
ce426f
    
ce426f
    Fix for values near a power of two, and some tidies.
ce426f
    
ce426f
    	[BZ #16739]
ce426f
    	* sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c (__nextafterl): Correct
ce426f
    	output when value is near a power of two.  Use int64_t for lx and
ce426f
    	remove casts.  Use decimal rather than hex exponent constants.
ce426f
    	Don't use long double multiplication when double will suffice.
ce426f
    	* math/libm-test.inc (nextafter_test_data): Add tests.
ce426f
    	* NEWS: Add 16739 and 16786 to bug list.
ce426f
ce426f
diff --git glibc-2.17-c758a686/math/libm-test.inc glibc-2.17-c758a686/math/libm-test.inc
ce426f
index 19194f6..967b679 100644
ce426f
--- glibc-2.17-c758a686/math/libm-test.inc
ce426f
+++ glibc-2.17-c758a686/math/libm-test.inc
ce426f
@@ -8199,6 +8208,14 @@ pow_test (void)
ce426f
 #if defined TEST_DOUBLE || defined TEST_LDOUBLE
ce426f
   TEST_ff_f (pow, -7.49321e+133, -9.80818e+16, 0, UNDERFLOW_EXCEPTION);
ce426f
 #endif
ce426f
+#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 106
ce426f
+    TEST_ff_f (nextafter, 1.0L, -10.0L, 1.0L-0x1p-106L, NO_EXCEPTION),
ce426f
+    TEST_ff_f (nextafter, 1.0L, 10.0L, 1.0L+0x1p-105L, NO_EXCEPTION),
ce426f
+    TEST_ff_f (nextafter, 1.0L-0x1p-106L, 10.0L, 1.0L, NO_EXCEPTION),
ce426f
+    TEST_ff_f (nextafter, -1.0L, -10.0L, -1.0L-0x1p-105L, NO_EXCEPTION),
ce426f
+    TEST_ff_f (nextafter, -1.0L, 10.0L, -1.0L+0x1p-106L, NO_EXCEPTION),
ce426f
+    TEST_ff_f (nextafter, -1.0L+0x1p-106L, -10.0L, -1.0L, NO_EXCEPTION),
ce426f
+#endif
ce426f
 
ce426f
   TEST_ff_f (pow, -1.0, -0xffffff, -1.0);
ce426f
   TEST_ff_f (pow, -1.0, -0x1fffffe, 1.0);
ce426f
diff --git glibc-2.17-c758a686/sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c glibc-2.17-c758a686/sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c
ce426f
index 30b1540..bf57cb8 100644
ce426f
--- glibc-2.17-c758a686/sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c
ce426f
+++ glibc-2.17-c758a686/sysdeps/ieee754/ldbl-128ibm/s_nextafterl.c
ce426f
@@ -30,8 +30,7 @@ static char rcsid[] = "$NetBSD: $";
ce426f
 
ce426f
 long double __nextafterl(long double x, long double y)
ce426f
 {
ce426f
-	int64_t hx,hy,ihx,ihy;
ce426f
-	uint64_t lx;
ce426f
+	int64_t hx, hy, ihx, ihy, lx;
ce426f
 	double xhi, xlo, yhi;
ce426f
 
ce426f
 	ldbl_unpack (x, &xhi, &xlo;;
ce426f
@@ -79,19 +78,28 @@ long double __nextafterl(long double x, long double y)
ce426f
 	      u = math_opt_barrier (x);
ce426f
 	      x -= __LDBL_DENORM_MIN__;
ce426f
 	      if (ihx < 0x0360000000000000LL
ce426f
-		  || (hx > 0 && (int64_t) lx <= 0)
ce426f
-		  || (hx < 0 && (int64_t) lx > 1)) {
ce426f
+		  || (hx > 0 && lx <= 0)
ce426f
+		  || (hx < 0 && lx > 1)) {
ce426f
 		u = u * u;
ce426f
 		math_force_eval (u);		/* raise underflow flag */
ce426f
 	      }
ce426f
 	      return x;
ce426f
 	    }
ce426f
-	    if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */
ce426f
-	      INSERT_WORDS64 (yhi, hx & (0x7ffLL<<52));
ce426f
-	      u = yhi;
ce426f
-	      u *= 0x1.0000000000000p-105L;
ce426f
+	    /* If the high double is an exact power of two and the low
ce426f
+	       double is the opposite sign, then 1ulp is one less than
ce426f
+	       what we might determine from the high double.  Similarly
ce426f
+	       if X is an exact power of two, and positive, because
ce426f
+	       making it a little smaller will result in the exponent
ce426f
+	       decreasing by one and normalisation of the mantissa.   */
ce426f
+	    if ((hx & 0x000fffffffffffffLL) == 0
ce426f
+		&& ((lx != 0 && (hx ^ lx) < 0)
ce426f
+		    || (lx == 0 && hx >= 0)))
ce426f
+	      ihx -= 1LL << 52;
ce426f
+	    if (ihx < (106LL << 52)) { /* ulp will denormal */
ce426f
+	      INSERT_WORDS64 (yhi, ihx & (0x7ffLL<<52));
ce426f
+	      u = yhi * 0x1p-105;
ce426f
 	    } else {
ce426f
-	      INSERT_WORDS64 (yhi, (hx & (0x7ffLL<<52))-(0x069LL<<52));
ce426f
+	      INSERT_WORDS64 (yhi, (ihx & (0x7ffLL<<52))-(105LL<<52));
ce426f
 	      u = yhi;
ce426f
 	    }
ce426f
 	    return x - u;
ce426f
@@ -109,8 +117,8 @@ long double __nextafterl(long double x, long double y)
ce426f
 	      u = math_opt_barrier (x);
ce426f
 	      x += __LDBL_DENORM_MIN__;
ce426f
 	      if (ihx < 0x0360000000000000LL
ce426f
-		  || (hx > 0 && (int64_t) lx < 0 && lx != 0x8000000000000001LL)
ce426f
-		  || (hx < 0 && (int64_t) lx >= 0)) {
ce426f
+		  || (hx > 0 && lx < 0 && lx != 0x8000000000000001LL)
ce426f
+		  || (hx < 0 && lx >= 0)) {
ce426f
 		u = u * u;
ce426f
 		math_force_eval (u);		/* raise underflow flag */
ce426f
 	      }
ce426f
@@ -118,12 +126,21 @@ long double __nextafterl(long double x, long double y)
ce426f
 		x = -0.0L;
ce426f
 	      return x;
ce426f
 	    }
ce426f
-	    if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */
ce426f
-	      INSERT_WORDS64 (yhi, hx & (0x7ffLL<<52));
ce426f
-	      u = yhi;
ce426f
-	      u *= 0x1.0000000000000p-105L;
ce426f
+	    /* If the high double is an exact power of two and the low
ce426f
+	       double is the opposite sign, then 1ulp is one less than
ce426f
+	       what we might determine from the high double.  Similarly
ce426f
+	       if X is an exact power of two, and negative, because
ce426f
+	       making it a little larger will result in the exponent
ce426f
+	       decreasing by one and normalisation of the mantissa.   */
ce426f
+	    if ((hx & 0x000fffffffffffffLL) == 0
ce426f
+		&& ((lx != 0 && (hx ^ lx) < 0)
ce426f
+		    || (lx == 0 && hx < 0)))
ce426f
+	      ihx -= 1LL << 52;
ce426f
+	    if (ihx < (106LL << 52)) { /* ulp will denormal */
ce426f
+	      INSERT_WORDS64 (yhi, ihx & (0x7ffLL<<52));
ce426f
+	      u = yhi * 0x1p-105;
ce426f
 	    } else {
ce426f
-	      INSERT_WORDS64 (yhi, (hx & (0x7ffLL<<52))-(0x069LL<<52));
ce426f
+	      INSERT_WORDS64 (yhi, (ihx & (0x7ffLL<<52))-(105LL<<52));
ce426f
 	      u = yhi;
ce426f
 	    }
ce426f
 	    return x + u;