diff mbox

Fix tan missing underflows (bug 16517) [committed]

Message ID alpine.DEB.2.10.1508072310570.23922@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers Aug. 7, 2015, 11:11 p.m. UTC
Similar to various other bugs in this area, some tan implementations
do not raise the underflow exception for subnormal arguments, when the
result is tiny and inexact.  This patch forces the exception in a
similar way to previous fixes.

Tested for x86_64, x86, mips64 and powerpc.  Committed.

(auto-libm-test-out diffs omitted below.)

2015-08-07  Joseph Myers  <joseph@codesourcery.com>

	[BZ #16517]
	* sysdeps/ieee754/dbl-64/s_tan.c: Include <float.h>.
	(tan): Force underflow exception for arguments with small absolute
	value.
	* sysdeps/ieee754/flt-32/k_tanf.c: Include <float.h>.
	(__kernel_tanf): Force underflow exception for arguments with
	small absolute value.
	* sysdeps/ieee754/ldbl-128/k_tanl.c: Include <float.h>.
	(__kernel_tanl): Force underflow exception for arguments with
	small absolute value.
	* sysdeps/ieee754/ldbl-128ibm/k_tanl.c: Include <float.h>.
	(__kernel_tanl): Force underflow exception for arguments with
	small absolute value.
	* sysdeps/ieee754/ldbl-96/k_tanl.c: Include <float.h>.
	(__kernel_tanl): Force underflow exception for arguments with
	small absolute value.
	* math/auto-libm-test-in: Add more tests of tan.
	* math/auto-libm-test-out: Regenerated.
diff mbox

Patch

diff --git a/math/auto-libm-test-in b/math/auto-libm-test-in
index cc9b7fd..bb6d30e 100644
--- a/math/auto-libm-test-in
+++ b/math/auto-libm-test-in
@@ -2659,6 +2659,10 @@  tan 9
 tan 10
 tan -0x1.062a48p+0
 tan -0x1.4f69cp+0
+tan min
+tan -min
+tan min_subnorm
+tan -min_subnorm
 
 tanh 0
 tanh -0
diff --git a/sysdeps/ieee754/dbl-64/s_tan.c b/sysdeps/ieee754/dbl-64/s_tan.c
index dcb4aca..b4e3bd2 100644
--- a/sysdeps/ieee754/dbl-64/s_tan.c
+++ b/sysdeps/ieee754/dbl-64/s_tan.c
@@ -34,6 +34,7 @@ 
 /*********************************************************************/
 
 #include <errno.h>
+#include <float.h>
 #include "endian.h"
 #include <dla.h>
 #include "mpa.h"
@@ -91,6 +92,11 @@  tan (double x)
   /* (I) The case abs(x) <= 1.259e-8 */
   if (w <= g1.d)
     {
+      if (w < DBL_MIN)
+	{
+	  double force_underflow = x * x;
+	  math_force_eval (force_underflow);
+	}
       retval = x;
       goto ret;
     }
diff --git a/sysdeps/ieee754/flt-32/k_tanf.c b/sysdeps/ieee754/flt-32/k_tanf.c
index a67f36e..2f2076d 100644
--- a/sysdeps/ieee754/flt-32/k_tanf.c
+++ b/sysdeps/ieee754/flt-32/k_tanf.c
@@ -17,6 +17,7 @@ 
 static char rcsid[] = "$NetBSD: k_tanf.c,v 1.4 1995/05/10 20:46:39 jtc Exp $";
 #endif
 
+#include <float.h>
 #include <math.h>
 #include <math_private.h>
 static const float
@@ -48,7 +49,17 @@  float __kernel_tanf(float x, float y, int iy)
 	if(ix<0x39000000)			/* x < 2**-13 */
 	    {if((int)x==0) {			/* generate inexact */
 		if((ix|(iy+1))==0) return one/fabsf(x);
-		else return (iy==1)? x: -one/x;
+		else if (iy == 1)
+		  {
+		    if (fabsf (x) < FLT_MIN)
+		      {
+			float force_underflow = x * x;
+			math_force_eval (force_underflow);
+		      }
+		    return x;
+		  }
+		else
+		  return -one / x;
 	    }
 	    }
 	if(ix>=0x3f2ca140) { 			/* |x|>=0.6744 */
diff --git a/sysdeps/ieee754/ldbl-128/k_tanl.c b/sysdeps/ieee754/ldbl-128/k_tanl.c
index dfba2d9..6a6fa9f 100644
--- a/sysdeps/ieee754/ldbl-128/k_tanl.c
+++ b/sysdeps/ieee754/ldbl-128/k_tanl.c
@@ -56,6 +56,7 @@ 
  *		       = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
  */
 
+#include <float.h>
 #include <libc-internal.h>
 #include <math.h>
 #include <math_private.h>
@@ -98,8 +99,17 @@  __kernel_tanl (long double x, long double y, int iy)
 	  if ((ix | u.parts32.w1 | u.parts32.w2 | u.parts32.w3
 	       | (iy + 1)) == 0)
 	    return one / fabs (x);
+	  else if (iy == 1)
+	    {
+	      if (fabsl (x) < LDBL_MIN)
+		{
+		  long double force_underflow = x * x;
+		  math_force_eval (force_underflow);
+		}
+	      return x;
+	    }
 	  else
-	    return (iy == 1) ? x : -one / x;
+	    return -one / x;
 	}
     }
   if (ix >= 0x3ffe5942) /* |x| >= 0.6743316650390625 */
diff --git a/sysdeps/ieee754/ldbl-128ibm/k_tanl.c b/sysdeps/ieee754/ldbl-128ibm/k_tanl.c
index 7f1caee..e50cc88 100644
--- a/sysdeps/ieee754/ldbl-128ibm/k_tanl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/k_tanl.c
@@ -56,6 +56,7 @@ 
  *		       = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
  */
 
+#include <float.h>
 #include <libc-internal.h>
 #include <math.h>
 #include <math_private.h>
@@ -98,8 +99,17 @@  __kernel_tanl (long double x, long double y, int iy)
 	{
 	  if ((ix | lx | (iy + 1)) == 0)
 	    return one / fabs (x);
+	  else if (iy == 1)
+	    {
+	      if (fabsl (x) < LDBL_MIN)
+		{
+		  long double force_underflow = x * x;
+		  math_force_eval (force_underflow);
+		}
+	      return x;
+	    }
 	  else
-	    return (iy == 1) ? x : -one / x;
+	    return -one / x;
 	}
     }
   if (ix >= 0x3fe59420) /* |x| >= 0.6743316650390625 */
diff --git a/sysdeps/ieee754/ldbl-96/k_tanl.c b/sysdeps/ieee754/ldbl-96/k_tanl.c
index 31cd236..ae6821d 100644
--- a/sysdeps/ieee754/ldbl-96/k_tanl.c
+++ b/sysdeps/ieee754/ldbl-96/k_tanl.c
@@ -56,6 +56,7 @@ 
  *		       = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
  */
 
+#include <float.h>
 #include <math.h>
 #include <math_private.h>
 static const long double
@@ -94,8 +95,17 @@  __kernel_tanl (long double x, long double y, int iy)
 	{			/* generate inexact */
 	  if (x == 0 && iy == -1)
 	    return one / fabsl (x);
+	  else if (iy == 1)
+	    {
+	      if (absx < LDBL_MIN)
+		{
+		  long double force_underflow = x * x;
+		  math_force_eval (force_underflow);
+		}
+	      return x;
+	    }
 	  else
-	    return (iy == 1) ? x : -one / x;
+	    return -one / x;
 	}
     }
   if (absx >= 0.6743316650390625L)