2013-01-04  Joseph Myers  <joseph@codesourcery.com>

	[BZ #14994]
	* math/s_casinh.c (__casinh): Reduce finite argument to first
	quadrant then set signs of results at the end.
	* math/s_casinhf.c (__casinhf): Likewise.
	* math/s_casinhl.c (__casinhl): Likewise.
	* math/libm-test.inc (casin_test): Add more tests.
	(casinh_test): Likewise.
	* sysdeps/i386/fpu/libm-test-ulps: Update.
	* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.

Index: glibc-2.11.3/math/libm-test.inc
===================================================================
--- glibc-2.11.3.orig/math/libm-test.inc
+++ glibc-2.11.3/math/libm-test.inc
@@ -1337,6 +1337,35 @@ casin_test (void)
   TEST_c_c (casin, 1.5L, plus_zero, M_PI_2l, 0.9624236501192068949955178268487368462704L);
   TEST_c_c (casin, 1.5L, minus_zero, M_PI_2l, -0.9624236501192068949955178268487368462704L);
 
+  TEST_c_c (casin, 0x1p50L, 1.0L, 1.570796326794895731052901991514519103193L, 3.535050620855721078027883819436720218708e1L);
+  TEST_c_c (casin, 0x1p50L, -1.0L, 1.570796326794895731052901991514519103193L, -3.535050620855721078027883819436720218708e1L);
+  TEST_c_c (casin, -0x1p50L, 1.0L, -1.570796326794895731052901991514519103193L, 3.535050620855721078027883819436720218708e1L);
+  TEST_c_c (casin, -0x1p50L, -1.0L, -1.570796326794895731052901991514519103193L, -3.535050620855721078027883819436720218708e1L);
+  TEST_c_c (casin, 1.0L, 0x1p50L, 8.881784197001252323389053344720723756399e-16L, 3.535050620855721078027883819436759661753e1L);
+  TEST_c_c (casin, -1.0L, 0x1p50L, -8.881784197001252323389053344720723756399e-16L, 3.535050620855721078027883819436759661753e1L);
+  TEST_c_c (casin, 1.0L, -0x1p50L, 8.881784197001252323389053344720723756399e-16L, -3.535050620855721078027883819436759661753e1L);
+  TEST_c_c (casin, -1.0L, -0x1p50L, -8.881784197001252323389053344720723756399e-16L, -3.535050620855721078027883819436759661753e1L);
+#ifndef TEST_FLOAT
+  TEST_c_c (casin, 0x1p500L, 1.0L, 1.570796326794896619231321691639751442099L, 3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, 0x1p500L, -1.0L, 1.570796326794896619231321691639751442099L, -3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, -0x1p500L, 1.0L, -1.570796326794896619231321691639751442099L, 3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, -0x1p500L, -1.0L, -1.570796326794896619231321691639751442099L, -3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, 1.0L, 0x1p500L, 3.054936363499604682051979393213617699789e-151L, 3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, -1.0L, 0x1p500L, -3.054936363499604682051979393213617699789e-151L, 3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, 1.0L, -0x1p500L, 3.054936363499604682051979393213617699789e-151L, -3.472667374605326000180332928505464606058e2L);
+  TEST_c_c (casin, -1.0L, -0x1p500L, -3.054936363499604682051979393213617699789e-151L, -3.472667374605326000180332928505464606058e2L);
+#endif
+#if defined TEST_LDOUBLE && LDBL_MAX_EXP >= 16384
+  TEST_c_c (casin, 0x1p5000L, 1.0L, 1.570796326794896619231321691639751442099L, 3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, 0x1p5000L, -1.0L, 1.570796326794896619231321691639751442099L, -3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, -0x1p5000L, 1.0L, -1.570796326794896619231321691639751442099L, 3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, -0x1p5000L, -1.0L, -1.570796326794896619231321691639751442099L, -3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, 1.0L, 0x1p5000L, 7.079811261048172892385615158694057552948e-1506L, 3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, -1.0L, 0x1p5000L, -7.079811261048172892385615158694057552948e-1506L, 3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, 1.0L, -0x1p5000L, 7.079811261048172892385615158694057552948e-1506L, -3.466429049980286492395577839412341016946e3L);
+  TEST_c_c (casin, -1.0L, -0x1p5000L, -7.079811261048172892385615158694057552948e-1506L, -3.466429049980286492395577839412341016946e3L);
+#endif
+
   TEST_c_c (casin, 0.75L, 1.25L, 0.453276177638793913448921196101971749L, 1.13239363160530819522266333696834467L);
   TEST_c_c (casin, -2, -3, -0.57065278432109940071028387968566963L, -1.9833870299165354323470769028940395L);
 
@@ -1427,6 +1456,35 @@ casinh_test (void)
   TEST_c_c (casinh, 1.5L, plus_zero, 1.194763217287109304111930828519090523536L, plus_zero);
   TEST_c_c (casinh, 1.5L, minus_zero, 1.194763217287109304111930828519090523536L, minus_zero);
 
+  TEST_c_c (casinh, 0x1p50L, 1.0L, 3.535050620855721078027883819436759661753e1L, 8.881784197001252323389053344720723756399e-16L);
+  TEST_c_c (casinh, 0x1p50L, -1.0L, 3.535050620855721078027883819436759661753e1L, -8.881784197001252323389053344720723756399e-16L);
+  TEST_c_c (casinh, -0x1p50L, 1.0L, -3.535050620855721078027883819436759661753e1L, 8.881784197001252323389053344720723756399e-16L);
+  TEST_c_c (casinh, -0x1p50L, -1.0L, -3.535050620855721078027883819436759661753e1L, -8.881784197001252323389053344720723756399e-16L);
+  TEST_c_c (casinh, 1.0L, 0x1p50L, 3.535050620855721078027883819436720218708e1L, 1.570796326794895731052901991514519103193L);
+  TEST_c_c (casinh, -1.0L, 0x1p50L, -3.535050620855721078027883819436720218708e1L, 1.570796326794895731052901991514519103193L);
+  TEST_c_c (casinh, 1.0L, -0x1p50L, 3.535050620855721078027883819436720218708e1L, -1.570796326794895731052901991514519103193L);
+  TEST_c_c (casinh, -1.0L, -0x1p50L, -3.535050620855721078027883819436720218708e1L, -1.570796326794895731052901991514519103193L);
+#ifndef TEST_FLOAT
+  TEST_c_c (casinh, 0x1p500L, 1.0L, 3.472667374605326000180332928505464606058e2L, 3.054936363499604682051979393213617699789e-151L);
+  TEST_c_c (casinh, 0x1p500L, -1.0L, 3.472667374605326000180332928505464606058e2L, -3.054936363499604682051979393213617699789e-151L);
+  TEST_c_c (casinh, -0x1p500L, 1.0L, -3.472667374605326000180332928505464606058e2L, 3.054936363499604682051979393213617699789e-151L);
+  TEST_c_c (casinh, -0x1p500L, -1.0L, -3.472667374605326000180332928505464606058e2L, -3.054936363499604682051979393213617699789e-151L);
+  TEST_c_c (casinh, 1.0L, 0x1p500L, 3.472667374605326000180332928505464606058e2L, 1.570796326794896619231321691639751442099L);
+  TEST_c_c (casinh, -1.0L, 0x1p500L, -3.472667374605326000180332928505464606058e2L, 1.570796326794896619231321691639751442099L);
+  TEST_c_c (casinh, 1.0L, -0x1p500L, 3.472667374605326000180332928505464606058e2L, -1.570796326794896619231321691639751442099L);
+  TEST_c_c (casinh, -1.0L, -0x1p500L, -3.472667374605326000180332928505464606058e2L, -1.570796326794896619231321691639751442099L);
+#endif
+#if defined TEST_LDOUBLE && LDBL_MAX_EXP >= 16384
+  TEST_c_c (casinh, 0x1p5000L, 1.0L, 3.466429049980286492395577839412341016946e3L, 7.079811261048172892385615158694057552948e-1506L);
+  TEST_c_c (casinh, 0x1p5000L, -1.0L, 3.466429049980286492395577839412341016946e3L, -7.079811261048172892385615158694057552948e-1506L);
+  TEST_c_c (casinh, -0x1p5000L, 1.0L, -3.466429049980286492395577839412341016946e3L, 7.079811261048172892385615158694057552948e-1506L);
+  TEST_c_c (casinh, -0x1p5000L, -1.0L, -3.466429049980286492395577839412341016946e3L, -7.079811261048172892385615158694057552948e-1506L);
+  TEST_c_c (casinh, 1.0L, 0x1p5000L, 3.466429049980286492395577839412341016946e3L, 1.570796326794896619231321691639751442099L);
+  TEST_c_c (casinh, -1.0L, 0x1p5000L, -3.466429049980286492395577839412341016946e3L, 1.570796326794896619231321691639751442099L);
+  TEST_c_c (casinh, 1.0L, -0x1p5000L, 3.466429049980286492395577839412341016946e3L, -1.570796326794896619231321691639751442099L);
+  TEST_c_c (casinh, -1.0L, -0x1p5000L, -3.466429049980286492395577839412341016946e3L, -1.570796326794896619231321691639751442099L);
+#endif
+
   TEST_c_c (casinh, 0.75L, 1.25L, 1.03171853444778027336364058631006594L, 0.911738290968487636358489564316731207L);
   TEST_c_c (casinh, -2, -3, -1.9686379257930962917886650952454982L, -0.96465850440760279204541105949953237L);
 
Index: glibc-2.11.3/math/s_casinh.c
===================================================================
--- glibc-2.11.3.orig/math/s_casinh.c
+++ glibc-2.11.3/math/s_casinh.c
@@ -62,20 +62,24 @@ __casinh (__complex__ double x)
     }
   else
     {
+      double rx, ix;
       __complex__ double y;
 
-      __real__ y = (__real__ x - __imag__ x) * (__real__ x + __imag__ x) + 1.0;
-      __imag__ y = 2.0 * __real__ x * __imag__ x;
+      /* Avoid cancellation by reducing to the first quadrant.  */
+      rx = fabs (__real__ x);
+      ix = fabs (__imag__ x);
+
+      __real__ y = (rx - ix) * (rx + ix) + 1.0;
+      __imag__ y = 2.0 * rx * ix;
 
       y = __csqrt (y);
 
-      __real__ y += __real__ x;
-      __imag__ y += __imag__ x;
+      __real__ y += rx;
+      __imag__ y += ix;
 
       res = __clog (y);
 
-      /* Ensure zeros have correct sign and results are correct if
-	 very close to branch cuts.  */
+      /* Give results the correct sign for the original argument.  */
       __real__ res = __copysign (__real__ res, __real__ x);
       __imag__ res = __copysign (__imag__ res, __imag__ x);
     }
Index: glibc-2.11.3/math/s_casinhf.c
===================================================================
--- glibc-2.11.3.orig/math/s_casinhf.c
+++ glibc-2.11.3/math/s_casinhf.c
@@ -62,20 +62,24 @@ __casinhf (__complex__ float x)
     }
   else
     {
+      float rx, ix;
       __complex__ float y;
 
-      __real__ y = (__real__ x - __imag__ x) * (__real__ x + __imag__ x) + 1.0;
-      __imag__ y = 2.0 * __real__ x * __imag__ x;
+      /* Avoid cancellation by reducing to the first quadrant.  */
+      rx = fabsf (__real__ x);
+      ix = fabsf (__imag__ x);
+
+      __real__ y = (rx - ix) * (rx + ix) + 1.0;
+      __imag__ y = 2.0 * rx * ix;
 
       y = __csqrtf (y);
 
-      __real__ y += __real__ x;
-      __imag__ y += __imag__ x;
+      __real__ y += rx;
+      __imag__ y += ix;
 
       res = __clogf (y);
 
-      /* Ensure zeros have correct sign and results are correct if
-	 very close to branch cuts.  */
+      /* Give results the correct sign for the original argument.  */
       __real__ res = __copysignf (__real__ res, __real__ x);
       __imag__ res = __copysignf (__imag__ res, __imag__ x);
     }
Index: glibc-2.11.3/math/s_casinhl.c
===================================================================
--- glibc-2.11.3.orig/math/s_casinhl.c
+++ glibc-2.11.3/math/s_casinhl.c
@@ -62,20 +62,24 @@ __casinhl (__complex__ long double x)
     }
   else
     {
+      long double rx, ix;
       __complex__ long double y;
 
-      __real__ y = (__real__ x - __imag__ x) * (__real__ x + __imag__ x) + 1.0;
-      __imag__ y = 2.0 * __real__ x * __imag__ x;
+      /* Avoid cancellation by reducing to the first quadrant.  */
+      rx = fabsl (__real__ x);
+      ix = fabsl (__imag__ x);
+
+      __real__ y = (rx - ix) * (rx + ix) + 1.0;
+      __imag__ y = 2.0 * rx * ix;
 
       y = __csqrtl (y);
 
-      __real__ y += __real__ x;
-      __imag__ y += __imag__ x;
+      __real__ y += rx;
+      __imag__ y += ix;
 
       res = __clogl (y);
 
-      /* Ensure zeros have correct sign and results are correct if
-	 very close to branch cuts.  */
+      /* Give results the correct sign for the original argument.  */
       __real__ res = __copysignl (__real__ res, __real__ x);
       __imag__ res = __copysignl (__imag__ res, __imag__ x);
     }
Index: glibc-2.11.3/sysdeps/i386/fpu/libm-test-ulps
===================================================================
--- glibc-2.11.3.orig/sysdeps/i386/fpu/libm-test-ulps
+++ glibc-2.11.3/sysdeps/i386/fpu/libm-test-ulps
@@ -30,7 +30,11 @@ ldouble: 1
 # cacos
 Test "Imaginary part of: cacos (+0 + 0.5 i) == pi/2 - 0.4812118250596034474977589134243684231352 i":
 double: 2
+float: 1
 idouble: 2
+ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (+0 + 1.0 i) == pi/2 - 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -56,7 +60,11 @@ double: 1
 idouble: 1
 Test "Imaginary part of: cacos (-0 + 0.5 i) == pi/2 - 0.4812118250596034474977589134243684231352 i":
 double: 2
+float: 1
 idouble: 2
+ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (-0 + 1.0 i) == pi/2 - 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -85,6 +93,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (-1.5 - 0 i) == pi + 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -98,6 +108,9 @@ double: 1
 idouble: 1
 ildouble: 1
 ldouble: 1
+Test "Real part of: cacos (0.75 + 1.25 i) == 1.11752014915610270578240049553777969 - 1.13239363160530819522266333696834467 i":
+float: 1
+ifloat: 1
 Test "Imaginary part of: cacos (0.75 + 1.25 i) == 1.11752014915610270578240049553777969 - 1.13239363160530819522266333696834467 i":
 float: 1
 ifloat: 1
@@ -108,6 +121,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (1.5 - 0 i) == +0 + 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -196,7 +211,11 @@ ifloat: 1
 # casin
 Test "Imaginary part of: casin (+0 + 0.5 i) == +0 + 0.4812118250596034474977589134243684231352 i":
 double: 2
+float: 1
 idouble: 2
+ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (+0 + 1.0 i) == +0 + 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -222,7 +241,11 @@ double: 1
 idouble: 1
 Test "Imaginary part of: casin (-0 + 0.5 i) == -0 + 0.4812118250596034474977589134243684231352 i":
 double: 2
+float: 1
 idouble: 2
+ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (-0 + 1.0 i) == -0 + 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -251,6 +274,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (-1.5 - 0 i) == -pi/2 - 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -271,6 +296,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (1.5 - 0 i) == pi/2 - 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -287,17 +314,29 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-0 - 1.5 i) == -0.9624236501192068949955178268487368462704 - pi/2 i":
 double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-0.5 + +0 i) == -0.4812118250596034474977589134243684231352 + +0 i":
 double: 2
+float: 1
 idouble: 2
+ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-0.5 - 0 i) == -0.4812118250596034474977589134243684231352 - 0 i":
 double: 2
+float: 1
 idouble: 2
+ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-1.0 + +0 i) == -0.8813735870195430252326093249797923090282 + +0 i":
 double: 2
 float: 1
@@ -1188,7 +1227,9 @@ ldouble: 1
 
 Function: Real part of "cacos":
 double: 1
+float: 1
 idouble: 1
+ifloat: 1
 ildouble: 1
 ldouble: 1
 
Index: glibc-2.11.3/sysdeps/x86_64/fpu/libm-test-ulps
===================================================================
--- glibc-2.11.3.orig/sysdeps/x86_64/fpu/libm-test-ulps
+++ glibc-2.11.3/sysdeps/x86_64/fpu/libm-test-ulps
@@ -46,6 +46,8 @@ double: 2
 float: 1
 idouble: 2
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (+0 + 1.0 i) == pi/2 - 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -74,6 +76,8 @@ double: 2
 float: 1
 idouble: 2
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (-0 + 1.0 i) == pi/2 - 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -102,6 +106,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (-1.5 - 0 i) == pi + 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -115,6 +121,9 @@ double: 1
 idouble: 1
 ildouble: 1
 ldouble: 1
+Test "Real part of: cacos (0.75 + 1.25 i) == 1.11752014915610270578240049553777969 - 1.13239363160530819522266333696834467 i":
+float: 1
+ifloat: 1
 Test "Imaginary part of: cacos (0.75 + 1.25 i) == 1.11752014915610270578240049553777969 - 1.13239363160530819522266333696834467 i":
 float: 1
 ifloat: 1
@@ -125,6 +134,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: cacos (1.5 - 0 i) == +0 + 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -216,6 +227,8 @@ double: 2
 float: 1
 idouble: 2
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (+0 + 1.0 i) == +0 + 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -244,6 +257,8 @@ double: 2
 float: 1
 idouble: 2
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (-0 + 1.0 i) == -0 + 0.8813735870195430252326093249797923090282 i":
 double: 2
 float: 1
@@ -272,6 +287,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (-1.5 - 0 i) == -pi/2 - 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -292,6 +309,8 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Imaginary part of: casin (1.5 - 0 i) == pi/2 - 0.9624236501192068949955178268487368462704 i":
 ildouble: 1
 ldouble: 1
@@ -308,21 +327,29 @@ double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-0 - 1.5 i) == -0.9624236501192068949955178268487368462704 - pi/2 i":
 double: 1
 float: 1
 idouble: 1
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-0.5 + +0 i) == -0.4812118250596034474977589134243684231352 + +0 i":
 double: 2
 float: 1
 idouble: 2
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-0.5 - 0 i) == -0.4812118250596034474977589134243684231352 - 0 i":
 double: 2
 float: 1
 idouble: 2
 ifloat: 1
+ildouble: 1
+ldouble: 1
 Test "Real part of: casinh (-1.0 + +0 i) == -0.8813735870195430252326093249797923090282 + +0 i":
 double: 2
 float: 1
@@ -1249,7 +1276,9 @@ ldouble: 1
 
 Function: Real part of "cacos":
 double: 1
+float: 1
 idouble: 1
+ifloat: 1
 ildouble: 1
 ldouble: 1
 
