This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix tanf underflow close to pi/4 (bug 14154)


Bug 14154 is a spurious underflow exception from tanf on arguments
very close to an odd multiple of pi/4.  Where x is the distance of the
argument from an odd multiple of pi/4, the underflowing operation in
__kernel_tanf is

        r = y + z*(s*(r+v)+y);

where z is x squared and s is x cubed, y is 0 and r+v is small enough
that the multiple of the fifth power of x can underflow.  This patch
fixes the spurious exception by using a linear approximation when the
argument is close enough to pi/4 for the higher-order terms to be <
0.5ulp of the result.  The tests added are the closest binary values
above and below pi/4 and -pi/4, for each number of bits from 8 to 24,
to provide coverage of a range of values close to pi/4 and -pi/4.

Tested x86 and x86_64 and ulps updated accordingly.  (My testing did
not show any need to update any ulps on x86_64.)

2012-07-06  Joseph Myers  <joseph@codesourcery.com>

	[BZ #14154]
	* sysdeps/ieee754/flt-32/k_tanf.c (__kernel_tanf): Use linear
	approximation for values within 0x1p-13f of an odd multiple of
	pi/4.
	* math/libm-test.inc (tan_test): Do not allow spurious underflow
	exception.  Add more tests.
	* sysdeps/i386/fpu/libm-test-ulps: Update.

diff --git a/math/libm-test.inc b/math/libm-test.inc
index b87a40d..27c53a1 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -8405,13 +8405,50 @@ tan_test (void)
   TEST_f_f (tan, nan_value, nan_value);
   check_int ("errno for tan(NaN) == 0", errno, 0, 0, 0, 0);
 
-  /* Bug 14154: spurious exception may occur.  */
-  TEST_f_f (tan, M_PI_4l, 1, UNDERFLOW_EXCEPTION_OK_FLOAT);
+  TEST_f_f (tan, M_PI_4l, 1);
   TEST_f_f (tan, 0.75L, 0.931596459944072461165202756573936428L);
 
   TEST_f_f (tan, 0x1p65, -0.0472364872359047946798414219288370688827L);
   TEST_f_f (tan, -0x1p65, 0.0472364872359047946798414219288370688827L);
 
+  TEST_f_f (tan, 0xc.9p-4, 0.9995162902115457818029468900654150261381L);
+  TEST_f_f (tan, 0xc.908p-4, 0.9997603425502441410973077452249560802034L);
+  TEST_f_f (tan, 0xc.90cp-4, 0.9998823910588060302788513970802357770031L);
+  TEST_f_f (tan, 0xc.90ep-4, 0.9999434208994808753305784795924711152508L);
+  TEST_f_f (tan, 0xc.90fp-4, 0.9999739372166156702433266059635165160515L);
+  TEST_f_f (tan, 0xc.90f8p-4, 0.9999891957244072765118898375645469865764L);
+  TEST_f_f (tan, 0xc.90fcp-4, 0.9999968250656122402859679132395522927393L);
+  TEST_f_f (tan, 0xc.90fdp-4, 0.9999987324100083358016192309006353329444L);
+  TEST_f_f (tan, 0xc.90fd8p-4, 0.9999996860835706212861509874451585282616L);
+  TEST_f_f (tan, 0xc.90fdap-4, 0.9999999245021033010474530133665235922808L);
+  TEST_f_f (tan, 0xc.ap-4, 1.0073556597407272165371804539701396631519L);
+  TEST_f_f (tan, 0xc.98p-4, 1.0034282930863044654045449407466962736255L);
+  TEST_f_f (tan, 0xc.94p-4, 1.0014703786820082237342656561856877993328L);
+  TEST_f_f (tan, 0xc.92p-4, 1.0004928571392300571266638743539017593717L);
+  TEST_f_f (tan, 0xc.91p-4, 1.0000044544650244953647966900221905361131L);
+  TEST_f_f (tan, 0xc.90fep-4, 1.0000006397580424009014454926842136804016L);
+  TEST_f_f (tan, 0xc.90fdcp-4, 1.0000001629206928242190327320047489394217L);
+  TEST_f_f (tan, 0xc.90fdbp-4, 1.0000000437113909572052640953950483705005L);
+
+  TEST_f_f (tan, -0xc.9p-4, -0.9995162902115457818029468900654150261381L);
+  TEST_f_f (tan, -0xc.908p-4, -0.9997603425502441410973077452249560802034L);
+  TEST_f_f (tan, -0xc.90cp-4, -0.9998823910588060302788513970802357770031L);
+  TEST_f_f (tan, -0xc.90ep-4, -0.9999434208994808753305784795924711152508L);
+  TEST_f_f (tan, -0xc.90fp-4, -0.9999739372166156702433266059635165160515L);
+  TEST_f_f (tan, -0xc.90f8p-4, -0.9999891957244072765118898375645469865764L);
+  TEST_f_f (tan, -0xc.90fcp-4, -0.9999968250656122402859679132395522927393L);
+  TEST_f_f (tan, -0xc.90fdp-4, -0.9999987324100083358016192309006353329444L);
+  TEST_f_f (tan, -0xc.90fd8p-4, -0.9999996860835706212861509874451585282616L);
+  TEST_f_f (tan, -0xc.90fdap-4, -0.9999999245021033010474530133665235922808L);
+  TEST_f_f (tan, -0xc.ap-4, -1.0073556597407272165371804539701396631519L);
+  TEST_f_f (tan, -0xc.98p-4, -1.0034282930863044654045449407466962736255L);
+  TEST_f_f (tan, -0xc.94p-4, -1.0014703786820082237342656561856877993328L);
+  TEST_f_f (tan, -0xc.92p-4, -1.0004928571392300571266638743539017593717L);
+  TEST_f_f (tan, -0xc.91p-4, -1.0000044544650244953647966900221905361131L);
+  TEST_f_f (tan, -0xc.90fep-4, -1.0000006397580424009014454926842136804016L);
+  TEST_f_f (tan, -0xc.90fdcp-4, -1.0000001629206928242190327320047489394217L);
+  TEST_f_f (tan, -0xc.90fdbp-4, -1.0000000437113909572052640953950483705005L);
+
 #ifndef TEST_FLOAT
   TEST_f_f (tan, 1e22, -1.628778225606898878549375936939548513545L);
   TEST_f_f (tan, 0x1p1023, -0.6814476476066215012854144040167365190368L);
diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps
index ab02bde..9ea5ed6 100644
--- a/sysdeps/i386/fpu/libm-test-ulps
+++ b/sysdeps/i386/fpu/libm-test-ulps
@@ -2353,9 +2353,45 @@ double: 1
 idouble: 1
 
 # tan
+Test "tan (-0xc.90fdbp-4) == -1.0000000437113909572052640953950483705005":
+float: 1
+ifloat: 1
+Test "tan (-0xc.90fdcp-4) == -1.0000001629206928242190327320047489394217":
+float: 1
+ifloat: 1
+Test "tan (-0xc.90fep-4) == -1.0000006397580424009014454926842136804016":
+float: 1
+ifloat: 1
+Test "tan (-0xc.91p-4) == -1.0000044544650244953647966900221905361131":
+float: 1
+ifloat: 1
+Test "tan (-0xc.92p-4) == -1.0004928571392300571266638743539017593717":
+float: 1
+ifloat: 1
+Test "tan (-0xc.94p-4) == -1.0014703786820082237342656561856877993328":
+float: 1
+ifloat: 1
 Test "tan (0x1p16383) == 0.422722393732022337800504160054440141575":
 ildouble: 1
 ldouble: 1
+Test "tan (0xc.90fdbp-4) == 1.0000000437113909572052640953950483705005":
+float: 1
+ifloat: 1
+Test "tan (0xc.90fdcp-4) == 1.0000001629206928242190327320047489394217":
+float: 1
+ifloat: 1
+Test "tan (0xc.90fep-4) == 1.0000006397580424009014454926842136804016":
+float: 1
+ifloat: 1
+Test "tan (0xc.91p-4) == 1.0000044544650244953647966900221905361131":
+float: 1
+ifloat: 1
+Test "tan (0xc.92p-4) == 1.0004928571392300571266638743539017593717":
+float: 1
+ifloat: 1
+Test "tan (0xc.94p-4) == 1.0014703786820082237342656561856877993328":
+float: 1
+ifloat: 1
 Test "tan (1e22) == -1.628778225606898878549375936939548513545":
 ildouble: 1
 ldouble: 1
diff --git a/sysdeps/ieee754/flt-32/k_tanf.c b/sysdeps/ieee754/flt-32/k_tanf.c
index 9220606..be9a5d0 100644
--- a/sysdeps/ieee754/flt-32/k_tanf.c
+++ b/sysdeps/ieee754/flt-32/k_tanf.c
@@ -56,6 +56,8 @@ float __kernel_tanf(float x, float y, int iy)
 	    z = pio4-x;
 	    w = pio4lo-y;
 	    x = z+w; y = 0.0;
+	    if (fabsf (x) < 0x1p-13f)
+		return (1 - ((hx >> 30) & 2)) * iy * (1.0f - 2 * iy * x);
 	}
 	z	=  x*x;
 	w 	=  z*z;

-- 
Joseph S. Myers
joseph@codesourcery.com


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