OpenLIBM: Replace complex ACOSH functions
authorJohn Marino <draco@marino.st>
Thu, 16 Jul 2015 13:22:17 +0000 (15:22 +0200)
committerJohn Marino <draco@marino.st>
Thu, 16 Jul 2015 13:29:12 +0000 (15:29 +0200)
The regression tests revealed a bug in the OpenBSD complex COSH
function implementation.  The FreeBSD implementation has been brought in,
at least temporarily, to address the regression.

It is likely that the ASINH functions are deficient with the edge cases
as well, but they've been left alone for now.  The OpenBSD complex
functions implementation probably needs to be reviewed and reworked based
on my review of the OpenSolaris libm and FreeBSD msun implementations

contrib/openbsd_libm/include/global/complex.h
contrib/openbsd_libm/src/s_cacosh.c
contrib/openbsd_libm/src/s_cacoshf.c
contrib/openbsd_libm/src/s_cacoshl.c

index b29f5a7..d0bf132 100644 (file)
 #undef I
 #define I              _Complex_I
 
+#if __ISO_C_VISIBLE >= 2011
+#if __GNUC_PREREQ__(4, 7)
+#define        CMPLX(x, y)     __builtin_complex((double)(x), (double)(y))
+#define        CMPLXF(x, y)    __builtin_complex((float)(x), (float)(y))
+#define        CMPLXL(x, y)    __builtin_complex((long double)(x), (long double)(y))
+#elif defined __clang__
+#define        CMPLX(x, y)     ((double complex){ x, y })
+#define        CMPLXF(x, y)    ((float complex){ x, y })
+#define        CMPLXL(x, y)    ((long double complex){ x, y })
+#endif
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
 __BEGIN_DECLS
 /* 
  * Double versions of C99 functions
index 75af1a3..4ec23f4 100644 (file)
@@ -50,9 +50,21 @@ double complex
 cacosh(double complex z)
 {
        double complex w;
+       double rx, ry;
 
-       w = I * cacos (z);
-       return (w);
+       w = cacos (z);
+       rx = creal (w);
+       ry = cimag (w);
+       if (isnan(rx) && isnan(ry))
+               return (CMPLX(ry, rx));
+       /* cacosh(NaN + I*+-Inf) = +Inf + I*NaN */
+       /* cacosh(+-Inf + I*NaN) = +Inf + I*NaN */
+       if (isnan(rx))
+               return (CMPLX(fabs(ry), rx));
+       /* cacosh(0 + I*NaN) = NaN + I*NaN */
+       if (isnan(ry))
+               return (CMPLX(ry, ry));
+       return (CMPLX(fabs(ry), copysign(rx, cimag(z))));
 }
 
 #if    LDBL_MANT_DIG == DBL_MANT_DIG
index d81f784..fc1fd8f 100644 (file)
@@ -49,7 +49,16 @@ float complex
 cacoshf(float complex z)
 {
        float complex w;
+       float rx, ry;
 
-       w = I * cacosf (z);
-       return (w);
+       w = cacosf (z);
+       rx = crealf (w);
+       ry = cimagf (w);
+       if (isnan(rx) && isnan(ry))
+               return (CMPLXF(ry, rx));
+       if (isnan(rx))
+               return (CMPLXF(fabsf(ry), rx));
+       if (isnan(ry))
+               return (CMPLXF(ry, ry));
+       return (CMPLXF(fabsf(ry), copysignf(rx, cimagf(z))));
 }
index 67a2362..bd37953 100644 (file)
@@ -50,7 +50,16 @@ long double complex
 cacoshl(long double complex z)
 {
        long double complex w;
+       long double rx, ry;
 
-       w = I * cacosl(z);
-       return (w);
+       w = cacosl (z);
+       rx = creall (w);
+       ry = cimagl (w);
+       if (isnan(rx) && isnan(ry))
+               return (CMPLXL(ry, rx));
+       if (isnan(rx))
+               return (CMPLXL(fabsl(ry), rx));
+       if (isnan(ry))
+               return (CMPLXL(ry, ry));
+       return (CMPLXL(fabsl(ry), copysignl(rx, cimagl(z))));
 }