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 ctan, ctanh of subnormals in round-upwards mode (bug 14328)


Bug 14328 is inaccuracy from ctan and ctanh on certain cases of
subnormal inputs, in round-upwards mode only.

Consider the following code from ctan:

          double sinhix = __ieee754_sinh (__imag__ x);
          double coshix = __ieee754_cosh (__imag__ x);

          den = cosrx * cosrx + sinhix * sinhix;
          __real__ res = sinrx * cosrx / den;
          __imag__ res = sinhix * coshix / den;

If __imag__ x is subnormal, sinh (__imag__ x) is very close to x (but
slightly bigger) and cosh (__imag__ x) is very close to 1 (but
slightly bigger). In fact, sinh does not honour the rounding mode for
subnormal inputs (it just returns the input), but cosh does honour the
rounding mode in this case (and returns a value 1ulp above 1).  sinhix
* coshix is then (rounded upwards) a subnormal value 1ulp above x.  If
cosrx is close to 0 (__real__ x close to an odd multiple of pi/2),
then the scaling up on division by den magnifies the 1ulp error on the
subnormal sinhix * coshix to a much larger error in the final
imaginary part of the result.

This patch fixes this issue by using x and 1 instead of calling sinh
and cosh, for fabs (__imag__ x) <= DBL_MIN.  To avoid spurious
underflow exceptions, the multiplication sinhix * sinhix must also be
avoided if that would underflow.  The condition fabs (sinhix) > fabs
(cosrx) * DBL_EPSILON is used for when to perform the multiplication;
if false, the multiplication certainly isn't needed[*], while if true,
the multiplication won't result in underflow (cos values of
floating-point numbers never get that close to 0).

Tested x86_64 and x86 and ulps updated accordingly.

The same issue applies in principle to calls to sincos in various
complex functions (cexp ccos ccosh csin csinh ctan ctanh), with a
similar fix (use x and 1 for tiny x rather than calling sincos).  But
it looks like none of the current sincos implementations honour the
rounding mode for subnormal inputs, so I think the issue is latent
there; I propose to address it (making the functions more robust) in
separate patches.

[*] Actually, sqrt (DBL_EPSILON) would be more like the right thing
here.  But there's no macro for that and I'd rather not rely on it
being constant folded; I don't think GCC will constant-fold much at
all for ldbl128-ibm.

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

	[BZ #14328]
	* math/s_ctan.c (__ctan): Do not call sinh and cosh for subnormals
	or multiply small sinh result by itself.
	* math/s_ctanf.c (__ctanf): Likewise.
	* math/s_ctanh.c (__ctanh): Likewise.
	* math/s_ctanhf.c (__ctanhf): Likewise.
	* math/s_ctanhl.c (__ctanhl): Likewise.
	* math/s_ctanl.c (__ctanl): Likewise.
	* math/libm-test.inc (ctan_test_tonearest): New function.
	(ctan_test_towardzero): Likewise.
	(ctan_test_downward): Likewise.
	(ctan_test_upward): Likewise.
	(ctanh_test_tonearest): Likewise.
	(ctanh_test_towardzero): Likewise.
	(ctanh_test_downward): Likewise.
	(ctanh_test_upward): Likewise.
	(main): Call these new functions.
	* sysdeps/i386/fpu/libm-test-ulps: Update.
	* sysdeps/x86_64/fpu/libm-test-ulps: Likewise.

diff --git a/math/libm-test.inc b/math/libm-test.inc
index 3e33348..514ad06 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -3319,6 +3319,138 @@ ctan_test (void)
 
 
 static void
+ctan_test_tonearest (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctan_tonearest);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_TONEAREST))
+    {
+      TEST_c_c (ctan, 0x1.921fb6p+0, 0x1p-149, -2.287733242885645987394874673945769518150e7L, 7.334008549954377778731880988481078535821e-31L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctan, 0x1.921fb54442d18p+0, 0x1p-1074, 1.633123935319536975596773704152891653086e16L, 1.317719414943508315995636961402669067843e-291L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctan, 0x1.921fb54442d1846ap+0L, 0x1p-16445L, -3.986797629811710706723242948653362815645e19L, 5.793882568875674066286163141055208625180e-4912L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctan_tonearest, complex);
+}
+
+
+static void
+ctan_test_towardzero (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctan_towardzero);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_TOWARDZERO))
+    {
+      TEST_c_c (ctan, 0x1.921fb6p+0, 0x1p-149, -2.287733242885645987394874673945769518150e7L, 7.334008549954377778731880988481078535821e-31L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctan, 0x1.921fb54442d18p+0, 0x1p-1074, 1.633123935319536975596773704152891653086e16L, 1.317719414943508315995636961402669067843e-291L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctan, 0x1.921fb54442d1846ap+0L, 0x1p-16445L, -3.986797629811710706723242948653362815645e19L, 5.793882568875674066286163141055208625180e-4912L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctan_towardzero, complex);
+}
+
+
+static void
+ctan_test_downward (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctan_downward);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_DOWNWARD))
+    {
+      TEST_c_c (ctan, 0x1.921fb6p+0, 0x1p-149, -2.287733242885645987394874673945769518150e7L, 7.334008549954377778731880988481078535821e-31L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctan, 0x1.921fb54442d18p+0, 0x1p-1074, 1.633123935319536975596773704152891653086e16L, 1.317719414943508315995636961402669067843e-291L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctan, 0x1.921fb54442d1846ap+0L, 0x1p-16445L, -3.986797629811710706723242948653362815645e19L, 5.793882568875674066286163141055208625180e-4912L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctan_downward, complex);
+}
+
+
+static void
+ctan_test_upward (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctan) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctan_upward);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_UPWARD))
+    {
+      TEST_c_c (ctan, 0x1.921fb6p+0, 0x1p-149, -2.287733242885645987394874673945769518150e7L, 7.334008549954377778731880988481078535821e-31L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctan, 0x1.921fb54442d18p+0, 0x1p-1074, 1.633123935319536975596773704152891653086e16L, 1.317719414943508315995636961402669067843e-291L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctan, 0x1.921fb54442d1846ap+0L, 0x1p-16445L, -3.986797629811710706723242948653362815645e19L, 5.793882568875674066286163141055208625180e-4912L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctan_upward, complex);
+}
+
+
+static void
 ctanh_test (void)
 {
   errno = 0;
@@ -3408,6 +3540,138 @@ ctanh_test (void)
 
 
 static void
+ctanh_test_tonearest (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctanh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctanh_tonearest);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_TONEAREST))
+    {
+      TEST_c_c (ctanh, 0x1p-149, 0x1.921fb6p+0, 7.334008549954377778731880988481078535821e-31L, -2.287733242885645987394874673945769518150e7L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctanh, 0x1p-1074, 0x1.921fb54442d18p+0, 1.317719414943508315995636961402669067843e-291L, 1.633123935319536975596773704152891653086e16L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctanh, 0x1p-16445L, 0x1.921fb54442d1846ap+0L, 5.793882568875674066286163141055208625180e-4912L, -3.986797629811710706723242948653362815645e19L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctanh_tonearest, complex);
+}
+
+
+static void
+ctanh_test_towardzero (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctanh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctanh_towardzero);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_TOWARDZERO))
+    {
+      TEST_c_c (ctanh, 0x1p-149, 0x1.921fb6p+0, 7.334008549954377778731880988481078535821e-31L, -2.287733242885645987394874673945769518150e7L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctanh, 0x1p-1074, 0x1.921fb54442d18p+0, 1.317719414943508315995636961402669067843e-291L, 1.633123935319536975596773704152891653086e16L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctanh, 0x1p-16445L, 0x1.921fb54442d1846ap+0L, 5.793882568875674066286163141055208625180e-4912L, -3.986797629811710706723242948653362815645e19L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctanh_towardzero, complex);
+}
+
+
+static void
+ctanh_test_downward (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctanh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctanh_downward);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_DOWNWARD))
+    {
+      TEST_c_c (ctanh, 0x1p-149, 0x1.921fb6p+0, 7.334008549954377778731880988481078535821e-31L, -2.287733242885645987394874673945769518150e7L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctanh, 0x1p-1074, 0x1.921fb54442d18p+0, 1.317719414943508315995636961402669067843e-291L, 1.633123935319536975596773704152891653086e16L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctanh, 0x1p-16445L, 0x1.921fb54442d1846ap+0L, 5.793882568875674066286163141055208625180e-4912L, -3.986797629811710706723242948653362815645e19L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctanh_downward, complex);
+}
+
+
+static void
+ctanh_test_upward (void)
+{
+  int save_round_mode;
+  errno = 0;
+  FUNC(ctanh) (BUILD_COMPLEX (0.7L, 1.2L));
+  if (errno == ENOSYS)
+    /* Function not implemented.  */
+    return;
+
+  START (ctanh_upward);
+
+  save_round_mode = fegetround ();
+
+  if (!fesetround (FE_UPWARD))
+    {
+      TEST_c_c (ctanh, 0x1p-149, 0x1.921fb6p+0, 7.334008549954377778731880988481078535821e-31L, -2.287733242885645987394874673945769518150e7L);
+
+#ifndef TEST_FLOAT
+      TEST_c_c (ctanh, 0x1p-1074, 0x1.921fb54442d18p+0, 1.317719414943508315995636961402669067843e-291L, 1.633123935319536975596773704152891653086e16L);
+#endif
+
+#if defined TEST_LDOUBLE && LDBL_MIN_EXP <= -16381
+      TEST_c_c (ctanh, 0x1p-16445L, 0x1.921fb54442d1846ap+0L, 5.793882568875674066286163141055208625180e-4912L, -3.986797629811710706723242948653362815645e19L);
+#endif
+    }
+
+  fesetround (save_round_mode);
+
+  END (ctanh_upward, complex);
+}
+
+
+static void
 erf_test (void)
 {
   errno = 0;
@@ -8909,7 +9173,15 @@ main (int argc, char **argv)
   csinh_test ();
   csqrt_test ();
   ctan_test ();
+  ctan_test_tonearest ();
+  ctan_test_towardzero ();
+  ctan_test_downward ();
+  ctan_test_upward ();
   ctanh_test ();
+  ctanh_test_tonearest ();
+  ctanh_test_towardzero ();
+  ctanh_test_downward ();
+  ctanh_test_upward ();
 
   /* Bessel functions:  */
   j0_test ();
diff --git a/math/s_ctan.c b/math/s_ctan.c
index 78117b3..89c0fef 100644
--- a/math/s_ctan.c
+++ b/math/s_ctan.c
@@ -83,10 +83,22 @@ __ctan (__complex__ double x)
 	}
       else
 	{
-	  double sinhix = __ieee754_sinh (__imag__ x);
-	  double coshix = __ieee754_cosh (__imag__ x);
+	  double sinhix, coshix;
+	  if (fabs (__imag__ x) > DBL_MIN)
+	    {
+	      sinhix = __ieee754_sinh (__imag__ x);
+	      coshix = __ieee754_cosh (__imag__ x);
+	    }
+	  else
+	    {
+	      sinhix = __imag__ x;
+	      coshix = 1.0;
+	    }
 
-	  den = cosrx * cosrx + sinhix * sinhix;
+	  if (fabs (sinhix) > fabs (cosrx) * DBL_EPSILON)
+	    den = cosrx * cosrx + sinhix * sinhix;
+	  else
+	    den = cosrx * cosrx;
 	  __real__ res = sinrx * cosrx / den;
 	  __imag__ res = sinhix * coshix / den;
 	}
diff --git a/math/s_ctanf.c b/math/s_ctanf.c
index 4cba559..2559f83 100644
--- a/math/s_ctanf.c
+++ b/math/s_ctanf.c
@@ -83,10 +83,22 @@ __ctanf (__complex__ float x)
 	}
       else
 	{
-	  float sinhix = __ieee754_sinhf (__imag__ x);
-	  float coshix = __ieee754_coshf (__imag__ x);
+	  float sinhix, coshix;
+	  if (fabsf (__imag__ x) > FLT_MIN)
+	    {
+	      sinhix = __ieee754_sinhf (__imag__ x);
+	      coshix = __ieee754_coshf (__imag__ x);
+	    }
+	  else
+	    {
+	      sinhix = __imag__ x;
+	      coshix = 1.0f;
+	    }
 
-	  den = cosrx * cosrx + sinhix * sinhix;
+	  if (fabsf (sinhix) > fabsf (cosrx) * FLT_EPSILON)
+	    den = cosrx * cosrx + sinhix * sinhix;
+	  else
+	    den = cosrx * cosrx;
 	  __real__ res = sinrx * cosrx / den;
 	  __imag__ res = sinhix * coshix / den;
 	}
diff --git a/math/s_ctanh.c b/math/s_ctanh.c
index 201871e..d288b7d 100644
--- a/math/s_ctanh.c
+++ b/math/s_ctanh.c
@@ -83,10 +83,22 @@ __ctanh (__complex__ double x)
 	}
       else
 	{
-	  double sinhrx = __ieee754_sinh (__real__ x);
-	  double coshrx = __ieee754_cosh (__real__ x);
+	  double sinhrx, coshrx;
+	  if (fabs (__real__ x) > DBL_MIN)
+	    {
+	      sinhrx = __ieee754_sinh (__real__ x);
+	      coshrx = __ieee754_cosh (__real__ x);
+	    }
+	  else
+	    {
+	      sinhrx = __real__ x;
+	      coshrx = 1.0;
+	    }
 
-	  den = sinhrx * sinhrx + cosix * cosix;
+	  if (fabs (sinhrx) > fabs (cosix) * DBL_EPSILON)
+	    den = sinhrx * sinhrx + cosix * cosix;
+	  else
+	    den = cosix * cosix;
 	  __real__ res = sinhrx * coshrx / den;
 	  __imag__ res = sinix * cosix / den;
 	}
diff --git a/math/s_ctanhf.c b/math/s_ctanhf.c
index e505155..ca36a83 100644
--- a/math/s_ctanhf.c
+++ b/math/s_ctanhf.c
@@ -83,10 +83,22 @@ __ctanhf (__complex__ float x)
 	}
       else
 	{
-	  float sinhrx = __ieee754_sinhf (__real__ x);
-	  float coshrx = __ieee754_coshf (__real__ x);
+	  float sinhrx, coshrx;
+	  if (fabsf (__real__ x) > FLT_MIN)
+	    {
+	      sinhrx = __ieee754_sinhf (__real__ x);
+	      coshrx = __ieee754_coshf (__real__ x);
+	    }
+	  else
+	    {
+	      sinhrx = __real__ x;
+	      coshrx = 1.0f;
+	    }
 
-	  den = sinhrx * sinhrx + cosix * cosix;
+	  if (fabsf (sinhrx) > fabsf (cosix) * FLT_EPSILON)
+	    den = sinhrx * sinhrx + cosix * cosix;
+	  else
+	    den = cosix * cosix;
 	  __real__ res = sinhrx * coshrx / den;
 	  __imag__ res = sinix * cosix / den;
 	}
diff --git a/math/s_ctanhl.c b/math/s_ctanhl.c
index e5d6779..dbf1612 100644
--- a/math/s_ctanhl.c
+++ b/math/s_ctanhl.c
@@ -83,10 +83,22 @@ __ctanhl (__complex__ long double x)
 	}
       else
 	{
-	  long double sinhrx = __ieee754_sinhl (__real__ x);
-	  long double coshrx = __ieee754_coshl (__real__ x);
+	  long double sinhrx, coshrx;
+	  if (fabsl (__real__ x) > LDBL_MIN)
+	    {
+	      sinhrx = __ieee754_sinhl (__real__ x);
+	      coshrx = __ieee754_coshl (__real__ x);
+	    }
+	  else
+	    {
+	      sinhrx = __real__ x;
+	      coshrx = 1.0L;
+	    }
 
-	  den = sinhrx * sinhrx + cosix * cosix;
+	  if (fabsl (sinhrx) > fabsl (cosix) * LDBL_EPSILON)
+	    den = sinhrx * sinhrx + cosix * cosix;
+	  else
+	    den = cosix * cosix;
 	  __real__ res = sinhrx * coshrx / den;
 	  __imag__ res = sinix * cosix / den;
 	}
diff --git a/math/s_ctanl.c b/math/s_ctanl.c
index 12d700c..4fe2611 100644
--- a/math/s_ctanl.c
+++ b/math/s_ctanl.c
@@ -83,10 +83,22 @@ __ctanl (__complex__ long double x)
 	}
       else
 	{
-	  long double sinhix = __ieee754_sinhl (__imag__ x);
-	  long double coshix = __ieee754_coshl (__imag__ x);
+	  long double sinhix, coshix;
+	  if (fabsl (__imag__ x) > LDBL_MIN)
+	    {
+	      sinhix = __ieee754_sinhl (__imag__ x);
+	      coshix = __ieee754_coshl (__imag__ x);
+	    }
+	  else
+	    {
+	      sinhix = __imag__ x;
+	      coshix = 1.0L;
+	    }
 
-	  den = cosrx * cosrx + sinhix * sinhix;
+	  if (fabsl (sinhix) > fabsl (cosrx) * LDBL_EPSILON)
+	    den = cosrx * cosrx + sinhix * sinhix;
+	  else
+	    den = cosrx * cosrx;
 	  __real__ res = sinrx * cosrx / den;
 	  __imag__ res = sinhix * coshix / den;
 	}
diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps
index 4661aea..6f41f02 100644
--- a/sysdeps/i386/fpu/libm-test-ulps
+++ b/sysdeps/i386/fpu/libm-test-ulps
@@ -1437,6 +1437,93 @@ idouble: 1
 ildouble: 2
 ldouble: 2
 
+# ctan_downward
+Test "Real part of: ctan_downward (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_downward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+double: 1
+idouble: 1
+ildouble: 2
+ldouble: 2
+Test "Imaginary part of: ctan_downward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 3
+ldouble: 3
+Test "Real part of: ctan_downward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 3
+ldouble: 3
+Test "Imaginary part of: ctan_downward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+# ctan_tonearest
+Test "Imaginary part of: ctan_tonearest (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_tonearest (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_tonearest (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+Test "Imaginary part of: ctan_tonearest (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+# ctan_towardzero
+Test "Real part of: ctan_towardzero (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+double: 1
+idouble: 1
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_towardzero (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_towardzero (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_towardzero (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+# ctan_upward
+Test "Real part of: ctan_upward (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 2
+ldouble: 2
+Test "Imaginary part of: ctan_upward (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_upward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_upward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+double: 1
+idouble: 1
+ildouble: 4
+ldouble: 4
+Test "Real part of: ctan_upward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+ildouble: 2
+ldouble: 2
+Test "Imaginary part of: ctan_upward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
 # ctanh
 Test "Real part of: ctanh (-2 - 3 i) == -0.965385879022133124278480269394560686 + 0.988437503832249372031403430350121098e-2 i":
 float: 1
@@ -1488,6 +1575,93 @@ idouble: 1
 ildouble: 2
 ldouble: 2
 
+# ctanh_downward
+Test "Real part of: ctanh_downward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 3
+ldouble: 3
+Test "Imaginary part of: ctanh_downward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+double: 1
+idouble: 1
+ildouble: 2
+ldouble: 2
+Test "Real part of: ctanh_downward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+Test "Imaginary part of: ctanh_downward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 3
+ldouble: 3
+Test "Imaginary part of: ctanh_downward (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 1
+ldouble: 1
+
+# ctanh_tonearest
+Test "Real part of: ctanh_tonearest (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctanh_tonearest (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_tonearest (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+Test "Real part of: ctanh_tonearest (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 1
+ldouble: 1
+
+# ctanh_towardzero
+Test "Real part of: ctanh_towardzero (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_towardzero (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+double: 1
+idouble: 1
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctanh_towardzero (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+Test "Imaginary part of: ctanh_towardzero (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+ildouble: 1
+ldouble: 1
+
+# ctanh_upward
+Test "Real part of: ctanh_upward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+double: 1
+idouble: 1
+ildouble: 4
+ldouble: 4
+Test "Imaginary part of: ctanh_upward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctanh_upward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_upward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+ildouble: 2
+ldouble: 2
+Test "Real part of: ctanh_upward (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_upward (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 2
+ldouble: 2
+
 # erf
 Test "erf (1.25) == 0.922900128256458230136523481197281140":
 double: 1
@@ -2878,6 +3052,56 @@ ifloat: 1
 ildouble: 1
 ldouble: 1
 
+Function: Real part of "ctan_downward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 3
+ldouble: 3
+
+Function: Imaginary part of "ctan_downward":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "ctan_tonearest":
+float: 1
+ifloat: 1
+
+Function: Imaginary part of "ctan_tonearest":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "ctan_towardzero":
+double: 1
+idouble: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "ctan_towardzero":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "ctan_upward":
+float: 1
+ifloat: 1
+ildouble: 2
+ldouble: 2
+
+Function: Imaginary part of "ctan_upward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
 Function: Real part of "ctanh":
 double: 1
 float: 1
@@ -2894,6 +3118,56 @@ ifloat: 1
 ildouble: 2
 ldouble: 2
 
+Function: Real part of "ctanh_downward":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "ctanh_downward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 3
+ldouble: 3
+
+Function: Real part of "ctanh_tonearest":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "ctanh_tonearest":
+float: 1
+ifloat: 1
+
+Function: Real part of "ctanh_towardzero":
+float: 3
+ifloat: 3
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "ctanh_towardzero":
+double: 1
+idouble: 1
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "ctanh_upward":
+double: 1
+float: 1
+idouble: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "ctanh_upward":
+float: 1
+ifloat: 1
+ildouble: 2
+ldouble: 2
+
 Function: "erf":
 double: 1
 idouble: 1
diff --git a/sysdeps/x86_64/fpu/libm-test-ulps b/sysdeps/x86_64/fpu/libm-test-ulps
index 3374b5f..765c7a0 100644
--- a/sysdeps/x86_64/fpu/libm-test-ulps
+++ b/sysdeps/x86_64/fpu/libm-test-ulps
@@ -1304,6 +1304,93 @@ Test "Real part of: ctan (1 + 47 i) == 2.729321264492904590777293425576722354636
 ildouble: 2
 ldouble: 2
 
+# ctan_downward
+Test "Real part of: ctan_downward (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_downward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 2
+ldouble: 2
+Test "Imaginary part of: ctan_downward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 3
+ldouble: 3
+Test "Real part of: ctan_downward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 3
+ldouble: 3
+Test "Imaginary part of: ctan_downward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+# ctan_tonearest
+Test "Imaginary part of: ctan_tonearest (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_tonearest (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_tonearest (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+Test "Imaginary part of: ctan_tonearest (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+# ctan_towardzero
+Test "Real part of: ctan_towardzero (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_towardzero (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_towardzero (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_towardzero (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+# ctan_upward
+Test "Real part of: ctan_upward (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 2
+ldouble: 2
+Test "Imaginary part of: ctan_upward (0x1.921fb54442d1846ap+0 + 0x1p-16445 i) == -3.986797629811710706723242948653362815645e19 + 5.793882568875674066286163141055208625180e-4912 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctan_upward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+double: 1
+idouble: 1
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctan_upward (0x1.921fb54442d18p+0 + 0x1p-1074 i) == 1.633123935319536975596773704152891653086e16 + 1.317719414943508315995636961402669067843e-291 i":
+ildouble: 4
+ldouble: 4
+Test "Real part of: ctan_upward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 2
+ldouble: 2
+Test "Imaginary part of: ctan_upward (0x1.921fb6p+0 + 0x1p-149 i) == -2.287733242885645987394874673945769518150e7 + 7.334008549954377778731880988481078535821e-31 i":
+double: 1
+float: 2
+idouble: 1
+ifloat: 2
+ildouble: 1
+ldouble: 1
+
 # ctanh
 Test "Real part of: ctanh (-2 - 3 i) == -0.965385879022133124278480269394560686 + 0.988437503832249372031403430350121098e-2 i":
 double: 1
@@ -1359,6 +1446,93 @@ Test "Imaginary part of: ctanh (47 + 1 i) == 1.0 + 2.729321264492904590777293425
 ildouble: 2
 ldouble: 2
 
+# ctanh_downward
+Test "Real part of: ctanh_downward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 3
+ldouble: 3
+Test "Imaginary part of: ctanh_downward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 2
+ldouble: 2
+Test "Real part of: ctanh_downward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+Test "Imaginary part of: ctanh_downward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 3
+ldouble: 3
+Test "Imaginary part of: ctanh_downward (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 1
+ldouble: 1
+
+# ctanh_tonearest
+Test "Real part of: ctanh_tonearest (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctanh_tonearest (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_tonearest (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+Test "Real part of: ctanh_tonearest (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 1
+ldouble: 1
+
+# ctanh_towardzero
+Test "Real part of: ctanh_towardzero (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_towardzero (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctanh_towardzero (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+Test "Imaginary part of: ctanh_towardzero (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+# ctanh_upward
+Test "Real part of: ctanh_upward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+ildouble: 4
+ldouble: 4
+Test "Imaginary part of: ctanh_upward (0x1p-1074 + 0x1.921fb54442d18p+0 i) == 1.317719414943508315995636961402669067843e-291 + 1.633123935319536975596773704152891653086e16 i":
+double: 1
+idouble: 1
+ildouble: 1
+ldouble: 1
+Test "Real part of: ctanh_upward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+double: 1
+float: 2
+idouble: 1
+ifloat: 2
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_upward (0x1p-149 + 0x1.921fb6p+0 i) == 7.334008549954377778731880988481078535821e-31 - 2.287733242885645987394874673945769518150e7 i":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 2
+ldouble: 2
+Test "Real part of: ctanh_upward (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 1
+ldouble: 1
+Test "Imaginary part of: ctanh_upward (0x1p-16445 + 0x1.921fb54442d1846ap+0 i) == 5.793882568875674066286163141055208625180e-4912 - 3.986797629811710706723242948653362815645e19 i":
+ildouble: 2
+ldouble: 2
+
 # erf
 Test "erf (1.25) == 0.922900128256458230136523481197281140":
 double: 1
@@ -2669,6 +2843,58 @@ ifloat: 1
 ildouble: 1
 ldouble: 1
 
+Function: Real part of "ctan_downward":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 3
+ldouble: 3
+
+Function: Imaginary part of "ctan_downward":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "ctan_tonearest":
+float: 1
+ifloat: 1
+
+Function: Imaginary part of "ctan_tonearest":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "ctan_towardzero":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "ctan_towardzero":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Real part of "ctan_upward":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 2
+ldouble: 2
+
+Function: Imaginary part of "ctan_upward":
+double: 1
+float: 2
+idouble: 1
+ifloat: 2
+ildouble: 4
+ldouble: 4
+
 Function: Real part of "ctanh":
 double: 1
 float: 1
@@ -2685,6 +2911,58 @@ ifloat: 2
 ildouble: 2
 ldouble: 2
 
+Function: Real part of "ctanh_downward":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "ctanh_downward":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 3
+ldouble: 3
+
+Function: Real part of "ctanh_tonearest":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Imaginary part of "ctanh_tonearest":
+float: 1
+ifloat: 1
+
+Function: Real part of "ctanh_towardzero":
+float: 1
+ifloat: 1
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "ctanh_towardzero":
+float: 1
+ifloat: 1
+ildouble: 1
+ldouble: 1
+
+Function: Real part of "ctanh_upward":
+double: 1
+float: 2
+idouble: 1
+ifloat: 2
+ildouble: 4
+ldouble: 4
+
+Function: Imaginary part of "ctanh_upward":
+double: 2
+float: 1
+idouble: 2
+ifloat: 1
+ildouble: 2
+ldouble: 2
+
 Function: "erf":
 double: 1
 idouble: 1

-- 
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]