about summary refs log tree commit diff
path: root/src/complex
diff options
context:
space:
mode:
Diffstat (limited to 'src/complex')
-rw-r--r--src/complex/__cexp.c87
-rw-r--r--src/complex/__cexpf.c68
-rw-r--r--src/complex/cabs.c6
-rw-r--r--src/complex/cabsf.c6
-rw-r--r--src/complex/cabsl.c13
-rw-r--r--src/complex/cacos.c11
-rw-r--r--src/complex/cacosf.c9
-rw-r--r--src/complex/cacosh.c9
-rw-r--r--src/complex/cacoshf.c7
-rw-r--r--src/complex/cacoshl.c14
-rw-r--r--src/complex/cacosl.c16
-rw-r--r--src/complex/carg.c6
-rw-r--r--src/complex/cargf.c6
-rw-r--r--src/complex/cargl.c13
-rw-r--r--src/complex/casin.c16
-rw-r--r--src/complex/casinf.c14
-rw-r--r--src/complex/casinh.c9
-rw-r--r--src/complex/casinhf.c7
-rw-r--r--src/complex/casinhl.c14
-rw-r--r--src/complex/casinl.c20
-rw-r--r--src/complex/catan.c119
-rw-r--r--src/complex/catanf.c115
-rw-r--r--src/complex/catanh.c9
-rw-r--r--src/complex/catanhf.c7
-rw-r--r--src/complex/catanhl.c14
-rw-r--r--src/complex/catanl.c126
-rw-r--r--src/complex/ccos.c8
-rw-r--r--src/complex/ccosf.c6
-rw-r--r--src/complex/ccosh.c140
-rw-r--r--src/complex/ccoshf.c90
-rw-r--r--src/complex/ccoshl.c7
-rw-r--r--src/complex/ccosl.c13
-rw-r--r--src/complex/cexp.c83
-rw-r--r--src/complex/cexpf.c83
-rw-r--r--src/complex/cexpl.c7
-rw-r--r--src/complex/cimag.c7
-rw-r--r--src/complex/cimagf.c7
-rw-r--r--src/complex/cimagl.c7
-rw-r--r--src/complex/clog.c14
-rw-r--r--src/complex/clogf.c12
-rw-r--r--src/complex/clogl.c18
-rw-r--r--src/complex/conj.c6
-rw-r--r--src/complex/conjf.c6
-rw-r--r--src/complex/conjl.c6
-rw-r--r--src/complex/cpow.c8
-rw-r--r--src/complex/cpowf.c6
-rw-r--r--src/complex/cpowl.c13
-rw-r--r--src/complex/cproj.c8
-rw-r--r--src/complex/cprojf.c8
-rw-r--r--src/complex/cprojl.c15
-rw-r--r--src/complex/creal.c6
-rw-r--r--src/complex/crealf.c6
-rw-r--r--src/complex/creall.c6
-rw-r--r--src/complex/csin.c9
-rw-r--r--src/complex/csinf.c7
-rw-r--r--src/complex/csinh.c141
-rw-r--r--src/complex/csinhf.c90
-rw-r--r--src/complex/csinhl.c7
-rw-r--r--src/complex/csinl.c14
-rw-r--r--src/complex/csqrt.c100
-rw-r--r--src/complex/csqrtf.c82
-rw-r--r--src/complex/csqrtl.c7
-rw-r--r--src/complex/ctan.c9
-rw-r--r--src/complex/ctanf.c7
-rw-r--r--src/complex/ctanh.c127
-rw-r--r--src/complex/ctanhf.c66
-rw-r--r--src/complex/ctanhl.c7
-rw-r--r--src/complex/ctanl.c14
68 files changed, 2024 insertions, 0 deletions
diff --git a/src/complex/__cexp.c b/src/complex/__cexp.c
new file mode 100644
index 00000000..f603e2be
--- /dev/null
+++ b/src/complex/__cexp.c
@@ -0,0 +1,87 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/k_exp.c */
+/*-
+ * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libm.h"
+
+static const uint32_t k = 1799; /* constant for reduction */
+static const double kln2 = 1246.97177782734161156; /* k * ln2 */
+
+/*
+ * Compute exp(x), scaled to avoid spurious overflow.  An exponent is
+ * returned separately in 'expt'.
+ *
+ * Input:  ln(DBL_MAX) <= x < ln(2 * DBL_MAX / DBL_MIN_DENORM) ~= 1454.91
+ * Output: 2**1023 <= y < 2**1024
+ */
+static double __frexp_exp(double x, int *expt)
+{
+	double exp_x;
+	uint32_t hx;
+
+	/*
+	 * We use exp(x) = exp(x - kln2) * 2**k, carefully chosen to
+	 * minimize |exp(kln2) - 2**k|.  We also scale the exponent of
+	 * exp_x to MAX_EXP so that the result can be multiplied by
+	 * a tiny number without losing accuracy due to denormalization.
+	 */
+	exp_x = exp(x - kln2);
+	GET_HIGH_WORD(hx, exp_x);
+	*expt = (hx >> 20) - (0x3ff + 1023) + k;
+	SET_HIGH_WORD(exp_x, (hx & 0xfffff) | ((0x3ff + 1023) << 20));
+	return exp_x;
+}
+
+/*
+ * __ldexp_cexp(x, expt) compute exp(x) * 2**expt.
+ * It is intended for large arguments (real part >= ln(DBL_MAX))
+ * where care is needed to avoid overflow.
+ *
+ * The present implementation is narrowly tailored for our hyperbolic and
+ * exponential functions.  We assume expt is small (0 or -1), and the caller
+ * has filtered out very large x, for which overflow would be inevitable.
+ */
+double complex __ldexp_cexp(double complex z, int expt)
+{
+	double x, y, exp_x, scale1, scale2;
+	int ex_expt, half_expt;
+
+	x = creal(z);
+	y = cimag(z);
+	exp_x = __frexp_exp(x, &ex_expt);
+	expt += ex_expt;
+
+	/*
+	 * Arrange so that scale1 * scale2 == 2**expt.  We use this to
+	 * compensate for scalbn being horrendously slow.
+	 */
+	half_expt = expt / 2;
+	INSERT_WORDS(scale1, (0x3ff + half_expt) << 20, 0);
+	half_expt = expt - half_expt;
+	INSERT_WORDS(scale2, (0x3ff + half_expt) << 20, 0);
+
+	return cpack(cos(y) * exp_x * scale1 * scale2, sin(y) * exp_x * scale1 * scale2);
+}
diff --git a/src/complex/__cexpf.c b/src/complex/__cexpf.c
new file mode 100644
index 00000000..47168e8f
--- /dev/null
+++ b/src/complex/__cexpf.c
@@ -0,0 +1,68 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/k_expf.c */
+/*-
+ * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libm.h"
+
+static const uint32_t k = 235; /* constant for reduction */
+static const float kln2 = 162.88958740F; /* k * ln2 */
+
+/*
+ * See __cexp.c for details.
+ *
+ * Input:  ln(FLT_MAX) <= x < ln(2 * FLT_MAX / FLT_MIN_DENORM) ~= 192.7
+ * Output: 2**127 <= y < 2**128
+ */
+static float __frexp_expf(float x, int *expt)
+{
+	float exp_x;
+	uint32_t hx;
+
+	exp_x = expf(x - kln2);
+	GET_FLOAT_WORD(hx, exp_x);
+	*expt = (hx >> 23) - (0x7f + 127) + k;
+	SET_FLOAT_WORD(exp_x, (hx & 0x7fffff) | ((0x7f + 127) << 23));
+	return exp_x;
+}
+
+float complex __ldexp_cexpf(float complex z, int expt)
+{
+	float x, y, exp_x, scale1, scale2;
+	int ex_expt, half_expt;
+
+	x = crealf(z);
+	y = cimagf(z);
+	exp_x = __frexp_expf(x, &ex_expt);
+	expt += ex_expt;
+
+	half_expt = expt / 2;
+	SET_FLOAT_WORD(scale1, (0x7f + half_expt) << 23);
+	half_expt = expt - half_expt;
+	SET_FLOAT_WORD(scale2, (0x7f + half_expt) << 23);
+
+	return cpackf(cosf(y) * exp_x * scale1 * scale2,
+	  sinf(y) * exp_x * scale1 * scale2);
+}
diff --git a/src/complex/cabs.c b/src/complex/cabs.c
new file mode 100644
index 00000000..f61d364e
--- /dev/null
+++ b/src/complex/cabs.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+double cabs(double complex z)
+{
+	return hypot(creal(z), cimag(z));
+}
diff --git a/src/complex/cabsf.c b/src/complex/cabsf.c
new file mode 100644
index 00000000..30b25c70
--- /dev/null
+++ b/src/complex/cabsf.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+float cabsf(float complex z)
+{
+	return hypotf(crealf(z), cimagf(z));
+}
diff --git a/src/complex/cabsl.c b/src/complex/cabsl.c
new file mode 100644
index 00000000..40a067c1
--- /dev/null
+++ b/src/complex/cabsl.c
@@ -0,0 +1,13 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double cabsl(long double complex z)
+{
+	return cabs(z);
+}
+#else
+long double cabsl(long double complex z)
+{
+	return hypotl(creall(z), cimagl(z));
+}
+#endif
diff --git a/src/complex/cacos.c b/src/complex/cacos.c
new file mode 100644
index 00000000..3aca0519
--- /dev/null
+++ b/src/complex/cacos.c
@@ -0,0 +1,11 @@
+#include "libm.h"
+
+// FIXME: Hull et al. "Implementing the complex arcsine and arccosine functions using exception handling" 1997
+
+/* acos(z) = pi/2 - asin(z) */
+
+double complex cacos(double complex z)
+{
+	z = casin(z);
+	return cpack(M_PI_2 - creal(z), -cimag(z));
+}
diff --git a/src/complex/cacosf.c b/src/complex/cacosf.c
new file mode 100644
index 00000000..563766e7
--- /dev/null
+++ b/src/complex/cacosf.c
@@ -0,0 +1,9 @@
+#include "libm.h"
+
+// FIXME
+
+float complex cacosf(float complex z)
+{
+	z = casinf(z);
+	return cpackf((float)M_PI_2 - crealf(z), -cimagf(z));
+}
diff --git a/src/complex/cacosh.c b/src/complex/cacosh.c
new file mode 100644
index 00000000..c2dfc1ba
--- /dev/null
+++ b/src/complex/cacosh.c
@@ -0,0 +1,9 @@
+#include "libm.h"
+
+/* acosh(z) = i acos(z) */
+
+double complex cacosh(double complex z)
+{
+	z = cacos(z);
+	return cpack(-cimag(z), creal(z));
+}
diff --git a/src/complex/cacoshf.c b/src/complex/cacoshf.c
new file mode 100644
index 00000000..37ff8800
--- /dev/null
+++ b/src/complex/cacoshf.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+float complex cacoshf(float complex z)
+{
+	z = cacosf(z);
+	return cpackf(-cimagf(z), crealf(z));
+}
diff --git a/src/complex/cacoshl.c b/src/complex/cacoshl.c
new file mode 100644
index 00000000..2a04e27b
--- /dev/null
+++ b/src/complex/cacoshl.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex cacoshl(long double complex z)
+{
+	return cacosh(z);
+}
+#else
+long double complex cacoshl(long double complex z)
+{
+	z = cacosl(z);
+	return cpackl(-cimagl(z), creall(z));
+}
+#endif
diff --git a/src/complex/cacosl.c b/src/complex/cacosl.c
new file mode 100644
index 00000000..5992e056
--- /dev/null
+++ b/src/complex/cacosl.c
@@ -0,0 +1,16 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex cacosl(long double complex z)
+{
+	return cacos(z);
+}
+#else
+// FIXME
+#define PI_2 1.57079632679489661923132169163975144L
+long double complex cacosl(long double complex z)
+{
+	z = casinl(z);
+	return cpackl(PI_2 - creall(z), -cimagl(z));
+}
+#endif
diff --git a/src/complex/carg.c b/src/complex/carg.c
new file mode 100644
index 00000000..d2d1b462
--- /dev/null
+++ b/src/complex/carg.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+double carg(double complex z)
+{
+	return atan2(cimag(z), creal(z));
+}
diff --git a/src/complex/cargf.c b/src/complex/cargf.c
new file mode 100644
index 00000000..ce183c4b
--- /dev/null
+++ b/src/complex/cargf.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+float cargf(float complex z)
+{
+	return atan2f(cimagf(z), crealf(z));
+}
diff --git a/src/complex/cargl.c b/src/complex/cargl.c
new file mode 100644
index 00000000..e0d50478
--- /dev/null
+++ b/src/complex/cargl.c
@@ -0,0 +1,13 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double cargl(long double complex z)
+{
+	return carg(z);
+}
+#else
+long double cargl(long double complex z)
+{
+	return atan2l(cimagl(z), creall(z));
+}
+#endif
diff --git a/src/complex/casin.c b/src/complex/casin.c
new file mode 100644
index 00000000..79aff278
--- /dev/null
+++ b/src/complex/casin.c
@@ -0,0 +1,16 @@
+#include "libm.h"
+
+// FIXME
+
+/* asin(z) = -i log(i z + sqrt(1 - z*z)) */
+
+double complex casin(double complex z)
+{
+	double complex w;
+	double x, y;
+
+	x = creal(z);
+	y = cimag(z);
+	w = cpack(1.0 - (x - y)*(x + y), -2.0*x*y);
+	return clog(cpack(-y, x) + csqrt(w));
+}
diff --git a/src/complex/casinf.c b/src/complex/casinf.c
new file mode 100644
index 00000000..cb9863f6
--- /dev/null
+++ b/src/complex/casinf.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+// FIXME
+
+float complex casinf(float complex z)
+{
+	float complex w;
+	float x, y;
+
+	x = crealf(z);
+	y = cimagf(z);
+	w = cpackf(1.0 - (x - y)*(x + y), -2.0*x*y);
+	return clogf(cpackf(-y, x) + csqrtf(w));
+}
diff --git a/src/complex/casinh.c b/src/complex/casinh.c
new file mode 100644
index 00000000..f2b3fef8
--- /dev/null
+++ b/src/complex/casinh.c
@@ -0,0 +1,9 @@
+#include "libm.h"
+
+/* asinh(z) = -i asin(i z) */
+
+double complex casinh(double complex z)
+{
+	z = casin(cpack(-cimag(z), creal(z)));
+	return cpack(cimag(z), -creal(z));
+}
diff --git a/src/complex/casinhf.c b/src/complex/casinhf.c
new file mode 100644
index 00000000..ed4af643
--- /dev/null
+++ b/src/complex/casinhf.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+float complex casinhf(float complex z)
+{
+	z = casinf(cpackf(-cimagf(z), crealf(z)));
+	return cpackf(cimagf(z), -crealf(z));
+}
diff --git a/src/complex/casinhl.c b/src/complex/casinhl.c
new file mode 100644
index 00000000..e5d80cef
--- /dev/null
+++ b/src/complex/casinhl.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex casinhl(long double complex z)
+{
+	return casinh(z);
+}
+#else
+long double complex casinhl(long double complex z)
+{
+	z = casinl(cpackl(-cimagl(z), creall(z)));
+	return cpackl(cimagl(z), -creall(z));
+}
+#endif
diff --git a/src/complex/casinl.c b/src/complex/casinl.c
new file mode 100644
index 00000000..f9aa8ded
--- /dev/null
+++ b/src/complex/casinl.c
@@ -0,0 +1,20 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex casinl(long double complex z)
+{
+	return casin(z);
+}
+#else
+// FIXME
+long double complex casinl(long double complex z)
+{
+	long double complex w;
+	long double x, y;
+
+	x = creall(z);
+	y = cimagl(z);
+	w = cpackl(1.0 - (x - y)*(x + y), -2.0*x*y);
+	return clogl(cpackl(-y, x) + csqrtl(w));
+}
+#endif
diff --git a/src/complex/catan.c b/src/complex/catan.c
new file mode 100644
index 00000000..39ce6cf2
--- /dev/null
+++ b/src/complex/catan.c
@@ -0,0 +1,119 @@
+/* origin: OpenBSD /usr/src/lib/libm/src/s_catan.c */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ *      Complex circular arc tangent
+ *
+ *
+ * SYNOPSIS:
+ *
+ * double complex catan();
+ * double complex z, w;
+ *
+ * w = catan (z);
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *          1       (    2x     )
+ * Re w  =  - arctan(-----------)  +  k PI
+ *          2       (     2    2)
+ *                  (1 - x  - y )
+ *
+ *               ( 2         2)
+ *          1    (x  +  (y+1) )
+ * Im w  =  - log(------------)
+ *          4    ( 2         2)
+ *               (x  +  (y-1) )
+ *
+ * Where k is an arbitrary integer.
+ *
+ * catan(z) = -i catanh(iz).
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5900       1.3e-16     7.8e-18
+ *    IEEE      -10,+10     30000       2.3e-15     8.5e-17
+ * The check catan( ctan(z) )  =  z, with |x| and |y| < PI/2,
+ * had peak relative error 1.5e-16, rms relative error
+ * 2.9e-17.  See also clog().
+ */
+
+#include "libm.h"
+
+#define MAXNUM 1.0e308
+
+static const double DP1 = 3.14159265160560607910E0;
+static const double DP2 = 1.98418714791870343106E-9;
+static const double DP3 = 1.14423774522196636802E-17;
+
+static double _redupi(double x)
+{
+	double t;
+	long i;
+
+	t = x/M_PI;
+	if (t >= 0.0)
+		t += 0.5;
+	else
+		t -= 0.5;
+
+	i = t;  /* the multiple */
+	t = i;
+	t = ((x - t * DP1) - t * DP2) - t * DP3;
+	return t;
+}
+
+double complex catan(double complex z)
+{
+	double complex w;
+	double a, t, x, x2, y;
+
+	x = creal(z);
+	y = cimag(z);
+
+	if (x == 0.0 && y > 1.0)
+		goto ovrf;
+
+	x2 = x * x;
+	a = 1.0 - x2 - (y * y);
+	if (a == 0.0)
+		goto ovrf;
+
+	t = 0.5 * atan2(2.0 * x, a);
+	w = _redupi(t);
+
+	t = y - 1.0;
+	a = x2 + (t * t);
+	if (a == 0.0)
+		goto ovrf;
+
+	t = y + 1.0;
+	a = (x2 + t * t)/a;
+	w = w + (0.25 * log(a)) * I;
+	return w;
+
+ovrf:
+	// FIXME
+	w = MAXNUM + MAXNUM * I;
+	return w;
+}
diff --git a/src/complex/catanf.c b/src/complex/catanf.c
new file mode 100644
index 00000000..8533bde3
--- /dev/null
+++ b/src/complex/catanf.c
@@ -0,0 +1,115 @@
+/* origin: OpenBSD /usr/src/lib/libm/src/s_catanf.c */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ *      Complex circular arc tangent
+ *
+ *
+ * SYNOPSIS:
+ *
+ * float complex catanf();
+ * float complex z, w;
+ *
+ * w = catanf( z );
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *          1       (    2x     )
+ * Re w  =  - arctan(-----------)  +  k PI
+ *          2       (     2    2)
+ *                  (1 - x  - y )
+ *
+ *               ( 2         2)
+ *          1    (x  +  (y+1) )
+ * Im w  =  - log(------------)
+ *          4    ( 2         2)
+ *               (x  +  (y-1) )
+ *
+ * Where k is an arbitrary integer.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    IEEE      -10,+10     30000        2.3e-6      5.2e-8
+ */
+
+#include "libm.h"
+
+#define MAXNUMF 1.0e38F
+
+static const double DP1 = 3.140625;
+static const double DP2 = 9.67502593994140625E-4;
+static const double DP3 = 1.509957990978376432E-7;
+
+static float _redupif(float xx)
+{
+	float x, t;
+	long i;
+
+	x = xx;
+	t = x/(float)M_PI;
+	if (t >= 0.0f)
+		t += 0.5f;
+	else
+		t -= 0.5f;
+
+	i = t;  /* the multiple */
+	t = i;
+	t = ((x - t * DP1) - t * DP2) - t * DP3;
+	return t;
+}
+
+float complex catanf(float complex z)
+{
+	float complex w;
+	float a, t, x, x2, y;
+
+	x = crealf(z);
+	y = cimagf(z);
+
+	if ((x == 0.0f) && (y > 1.0f))
+		goto ovrf;
+
+	x2 = x * x;
+	a = 1.0f - x2 - (y * y);
+	if (a == 0.0f)
+		goto ovrf;
+
+	t = 0.5f * atan2f(2.0f * x, a);
+	w = _redupif(t);
+
+	t = y - 1.0f;
+	a = x2 + (t * t);
+	if (a == 0.0f)
+		goto ovrf;
+
+	t = y + 1.0f;
+	a = (x2 + (t * t))/a;
+	w = w + (0.25f * logf (a)) * I;
+	return w;
+
+ovrf:
+	// FIXME
+	w = MAXNUMF + MAXNUMF * I;
+	return w;
+}
diff --git a/src/complex/catanh.c b/src/complex/catanh.c
new file mode 100644
index 00000000..b1628022
--- /dev/null
+++ b/src/complex/catanh.c
@@ -0,0 +1,9 @@
+#include "libm.h"
+
+/* atanh = -i atan(i z) */
+
+double complex catanh(double complex z)
+{
+	z = catan(cpack(-cimag(z), creal(z)));
+	return cpack(cimag(z), -creal(z));
+}
diff --git a/src/complex/catanhf.c b/src/complex/catanhf.c
new file mode 100644
index 00000000..e1d1e648
--- /dev/null
+++ b/src/complex/catanhf.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+float complex catanhf(float complex z)
+{
+	z = catanf(cpackf(-cimagf(z), crealf(z)));
+	return cpackf(cimagf(z), -crealf(z));
+}
diff --git a/src/complex/catanhl.c b/src/complex/catanhl.c
new file mode 100644
index 00000000..0a9374a3
--- /dev/null
+++ b/src/complex/catanhl.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex catanhl(long double complex z)
+{
+	return catanh(z);
+}
+#else
+long double complex catanhl(long double complex z)
+{
+	z = catanl(cpackl(-cimagl(z), creall(z)));
+	return cpackl(cimagl(z), -creall(z));
+}
+#endif
diff --git a/src/complex/catanl.c b/src/complex/catanl.c
new file mode 100644
index 00000000..5ace7704
--- /dev/null
+++ b/src/complex/catanl.c
@@ -0,0 +1,126 @@
+/* origin: OpenBSD /usr/src/lib/libm/src/s_catanl.c */
+/*
+ * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ *      Complex circular arc tangent
+ *
+ *
+ * SYNOPSIS:
+ *
+ * long double complex catanl();
+ * long double complex z, w;
+ *
+ * w = catanl( z );
+ *
+ *
+ * DESCRIPTION:
+ *
+ * If
+ *     z = x + iy,
+ *
+ * then
+ *          1       (    2x     )
+ * Re w  =  - arctan(-----------)  +  k PI
+ *          2       (     2    2)
+ *                  (1 - x  - y )
+ *
+ *               ( 2         2)
+ *          1    (x  +  (y+1) )
+ * Im w  =  - log(------------)
+ *          4    ( 2         2)
+ *               (x  +  (y-1) )
+ *
+ * Where k is an arbitrary integer.
+ *
+ *
+ * ACCURACY:
+ *
+ *                      Relative error:
+ * arithmetic   domain     # trials      peak         rms
+ *    DEC       -10,+10      5900       1.3e-16     7.8e-18
+ *    IEEE      -10,+10     30000       2.3e-15     8.5e-17
+ * The check catan( ctan(z) )  =  z, with |x| and |y| < PI/2,
+ * had peak relative error 1.5e-16, rms relative error
+ * 2.9e-17.  See also clog().
+ */
+
+#include <complex.h>
+#include <float.h>
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex catanl(long double complex z)
+{
+	return catan(z);
+}
+#else
+static const long double PIL = 3.141592653589793238462643383279502884197169L;
+static const long double DP1 = 3.14159265358979323829596852490908531763125L;
+static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L;
+static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L;
+
+static long double redupil(long double x)
+{
+	long double t;
+	long i;
+
+	t = x / PIL;
+	if (t >= 0.0L)
+		t += 0.5L;
+	else
+		t -= 0.5L;
+
+	i = t;  /* the multiple */
+	t = i;
+	t = ((x - t * DP1) - t * DP2) - t * DP3;
+	return t;
+}
+
+long double complex catanl(long double complex z)
+{
+	long double complex w;
+	long double a, t, x, x2, y;
+
+	x = creall(z);
+	y = cimagl(z);
+
+	if ((x == 0.0L) && (y > 1.0L))
+		goto ovrf;
+
+	x2 = x * x;
+	a = 1.0L - x2 - (y * y);
+	if (a == 0.0L)
+		goto ovrf;
+
+	t = atan2l(2.0L * x, a) * 0.5L;
+	w = redupil(t);
+
+	t = y - 1.0L;
+	a = x2 + (t * t);
+	if (a == 0.0L)
+		goto ovrf;
+
+	t = y + 1.0L;
+	a = (x2 + (t * t)) / a;
+	w = w + (0.25L * logl(a)) * I;
+	return w;
+
+ovrf:
+	// FIXME
+	w = LDBL_MAX + LDBL_MAX * I;
+	return w;
+}
+#endif
diff --git a/src/complex/ccos.c b/src/complex/ccos.c
new file mode 100644
index 00000000..5754c238
--- /dev/null
+++ b/src/complex/ccos.c
@@ -0,0 +1,8 @@
+#include "libm.h"
+
+/* cos(z) = cosh(i z) */
+
+double complex ccos(double complex z)
+{
+	return ccosh(cpack(-cimag(z), creal(z)));
+}
diff --git a/src/complex/ccosf.c b/src/complex/ccosf.c
new file mode 100644
index 00000000..9b72c4f4
--- /dev/null
+++ b/src/complex/ccosf.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+float complex ccosf(float complex z)
+{
+	return ccoshf(cpackf(-cimagf(z), crealf(z)));
+}
diff --git a/src/complex/ccosh.c b/src/complex/ccosh.c
new file mode 100644
index 00000000..81f29432
--- /dev/null
+++ b/src/complex/ccosh.c
@@ -0,0 +1,140 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_ccosh.c */
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Hyperbolic cosine of a complex argument z = x + i y.
+ *
+ * cosh(z) = cosh(x+iy)
+ *         = cosh(x) cos(y) + i sinh(x) sin(y).
+ *
+ * Exceptional values are noted in the comments within the source code.
+ * These values and the return value were taken from n1124.pdf.
+ */
+
+#include "libm.h"
+
+static const double huge = 0x1p1023;
+
+double complex ccosh(double complex z)
+{
+	double x, y, h;
+	int32_t hx, hy, ix, iy, lx, ly;
+
+	x = creal(z);
+	y = cimag(z);
+
+	EXTRACT_WORDS(hx, lx, x);
+	EXTRACT_WORDS(hy, ly, y);
+
+	ix = 0x7fffffff & hx;
+	iy = 0x7fffffff & hy;
+
+	/* Handle the nearly-non-exceptional cases where x and y are finite. */
+	if (ix < 0x7ff00000 && iy < 0x7ff00000) {
+		if ((iy | ly) == 0)
+			return cpack(cosh(x), x * y);
+		if (ix < 0x40360000)    /* small x: normal case */
+			return cpack(cosh(x) * cos(y), sinh(x) * sin(y));
+
+		/* |x| >= 22, so cosh(x) ~= exp(|x|) */
+		if (ix < 0x40862e42) {
+			/* x < 710: exp(|x|) won't overflow */
+			h = exp(fabs(x)) * 0.5;
+			return cpack(h * cos(y), copysign(h, x) * sin(y));
+		} else if (ix < 0x4096bbaa) {
+			/* x < 1455: scale to avoid overflow */
+			z = __ldexp_cexp(cpack(fabs(x), y), -1);
+			return cpack(creal(z), cimag(z) * copysign(1, x));
+		} else {
+			/* x >= 1455: the result always overflows */
+			h = huge * x;
+			return cpack(h * h * cos(y), h * sin(y));
+		}
+	}
+
+	/*
+	 * cosh(+-0 +- I Inf) = dNaN + I sign(d(+-0, dNaN))0.
+	 * The sign of 0 in the result is unspecified.  Choice = normally
+	 * the same as dNaN.  Raise the invalid floating-point exception.
+	 *
+	 * cosh(+-0 +- I NaN) = d(NaN) + I sign(d(+-0, NaN))0.
+	 * The sign of 0 in the result is unspecified.  Choice = normally
+	 * the same as d(NaN).
+	 */
+	if ((ix | lx) == 0 && iy >= 0x7ff00000)
+		return cpack(y - y, copysign(0, x * (y - y)));
+
+	/*
+	 * cosh(+-Inf +- I 0) = +Inf + I (+-)(+-)0.
+	 *
+	 * cosh(NaN +- I 0)   = d(NaN) + I sign(d(NaN, +-0))0.
+	 * The sign of 0 in the result is unspecified.
+	 */
+	if ((iy | ly) == 0 && ix >= 0x7ff00000) {
+		if (((hx & 0xfffff) | lx) == 0)
+			return cpack(x * x, copysign(0, x) * y);
+		return cpack(x * x, copysign(0, (x + x) * y));
+	}
+
+	/*
+	 * cosh(x +- I Inf) = dNaN + I dNaN.
+	 * Raise the invalid floating-point exception for finite nonzero x.
+	 *
+	 * cosh(x + I NaN) = d(NaN) + I d(NaN).
+	 * Optionally raises the invalid floating-point exception for finite
+	 * nonzero x.  Choice = don't raise (except for signaling NaNs).
+	 */
+	if (ix < 0x7ff00000 && iy >= 0x7ff00000)
+		return cpack(y - y, x * (y - y));
+
+	/*
+	 * cosh(+-Inf + I NaN)  = +Inf + I d(NaN).
+	 *
+	 * cosh(+-Inf +- I Inf) = +Inf + I dNaN.
+	 * The sign of Inf in the result is unspecified.  Choice = always +.
+	 * Raise the invalid floating-point exception.
+	 *
+	 * cosh(+-Inf + I y)   = +Inf cos(y) +- I Inf sin(y)
+	 */
+	if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) {
+		if (iy >= 0x7ff00000)
+			return cpack(x * x, x * (y - y));
+		return cpack((x * x) * cos(y), x * sin(y));
+	}
+
+	/*
+	 * cosh(NaN + I NaN)  = d(NaN) + I d(NaN).
+	 *
+	 * cosh(NaN +- I Inf) = d(NaN) + I d(NaN).
+	 * Optionally raises the invalid floating-point exception.
+	 * Choice = raise.
+	 *
+	 * cosh(NaN + I y)    = d(NaN) + I d(NaN).
+	 * Optionally raises the invalid floating-point exception for finite
+	 * nonzero y.  Choice = don't raise (except for signaling NaNs).
+	 */
+	return cpack((x * x) * (y - y), (x + x) * (y - y));
+}
diff --git a/src/complex/ccoshf.c b/src/complex/ccoshf.c
new file mode 100644
index 00000000..683e77fa
--- /dev/null
+++ b/src/complex/ccoshf.c
@@ -0,0 +1,90 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_ccoshf.c */
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Hyperbolic cosine of a complex argument.  See s_ccosh.c for details.
+ */
+
+#include "libm.h"
+
+static const float huge = 0x1p127;
+
+float complex ccoshf(float complex z)
+{
+	float x, y, h;
+	int32_t hx, hy, ix, iy;
+
+	x = crealf(z);
+	y = cimagf(z);
+
+	GET_FLOAT_WORD(hx, x);
+	GET_FLOAT_WORD(hy, y);
+
+	ix = 0x7fffffff & hx;
+	iy = 0x7fffffff & hy;
+
+	if (ix < 0x7f800000 && iy < 0x7f800000) {
+		if (iy == 0)
+			return cpackf(coshf(x), x * y);
+		if (ix < 0x41100000)    /* small x: normal case */
+			return cpackf(coshf(x) * cosf(y), sinhf(x) * sinf(y));
+
+		/* |x| >= 9, so cosh(x) ~= exp(|x|) */
+		if (ix < 0x42b17218) {
+			/* x < 88.7: expf(|x|) won't overflow */
+			h = expf(fabsf(x)) * 0.5f;
+			return cpackf(h * cosf(y), copysignf(h, x) * sinf(y));
+		} else if (ix < 0x4340b1e7) {
+			/* x < 192.7: scale to avoid overflow */
+			z = __ldexp_cexpf(cpackf(fabsf(x), y), -1);
+			return cpackf(crealf(z), cimagf(z) * copysignf(1, x));
+		} else {
+			/* x >= 192.7: the result always overflows */
+			h = huge * x;
+			return cpackf(h * h * cosf(y), h * sinf(y));
+		}
+	}
+
+	if (ix == 0 && iy >= 0x7f800000)
+		return cpackf(y - y, copysignf(0, x * (y - y)));
+
+	if (iy == 0 && ix >= 0x7f800000) {
+		if ((hx & 0x7fffff) == 0)
+			return cpackf(x * x, copysignf(0, x) * y);
+		return cpackf(x * x, copysignf(0, (x + x) * y));
+	}
+
+	if (ix < 0x7f800000 && iy >= 0x7f800000)
+		return cpackf(y - y, x * (y - y));
+
+	if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) {
+		if (iy >= 0x7f800000)
+			return cpackf(x * x, x * (y - y));
+		return cpackf((x * x) * cosf(y), x * sinf(y));
+	}
+
+	return cpackf((x * x) * (y - y), (x + x) * (y - y));
+}
diff --git a/src/complex/ccoshl.c b/src/complex/ccoshl.c
new file mode 100644
index 00000000..9b2aed9e
--- /dev/null
+++ b/src/complex/ccoshl.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+//FIXME
+long double complex ccoshl(long double complex z)
+{
+	return ccosh(z);
+}
diff --git a/src/complex/ccosl.c b/src/complex/ccosl.c
new file mode 100644
index 00000000..e37825a9
--- /dev/null
+++ b/src/complex/ccosl.c
@@ -0,0 +1,13 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex ccosl(long double complex z)
+{
+	return ccos(z);
+}
+#else
+long double complex ccosl(long double complex z)
+{
+	return ccoshl(cpackl(-cimagl(z), creall(z)));
+}
+#endif
diff --git a/src/complex/cexp.c b/src/complex/cexp.c
new file mode 100644
index 00000000..3b8bb752
--- /dev/null
+++ b/src/complex/cexp.c
@@ -0,0 +1,83 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_cexp.c */
+/*-
+ * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libm.h"
+
+static const uint32_t
+exp_ovfl  = 0x40862e42,  /* high bits of MAX_EXP * ln2 ~= 710 */
+cexp_ovfl = 0x4096b8e4;  /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */
+
+double complex cexp(double complex z)
+{
+	double x, y, exp_x;
+	uint32_t hx, hy, lx, ly;
+
+	x = creal(z);
+	y = cimag(z);
+
+	EXTRACT_WORDS(hy, ly, y);
+	hy &= 0x7fffffff;
+
+	/* cexp(x + I 0) = exp(x) + I 0 */
+	if ((hy | ly) == 0)
+		return cpack(exp(x), y);
+	EXTRACT_WORDS(hx, lx, x);
+	/* cexp(0 + I y) = cos(y) + I sin(y) */
+	if (((hx & 0x7fffffff) | lx) == 0)
+		return cpack(cos(y), sin(y));
+
+	if (hy >= 0x7ff00000) {
+		if (lx != 0 || (hx & 0x7fffffff) != 0x7ff00000) {
+			/* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */
+			return cpack(y - y, y - y);
+		} else if (hx & 0x80000000) {
+			/* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */
+			return cpack(0.0, 0.0);
+		} else {
+			/* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */
+			return cpack(x, y - y);
+		}
+	}
+
+	if (hx >= exp_ovfl && hx <= cexp_ovfl) {
+		/*
+		 * x is between 709.7 and 1454.3, so we must scale to avoid
+		 * overflow in exp(x).
+		 */
+		return __ldexp_cexp(z, 0);
+	} else {
+		/*
+		 * Cases covered here:
+		 *  -  x < exp_ovfl and exp(x) won't overflow (common case)
+		 *  -  x > cexp_ovfl, so exp(x) * s overflows for all s > 0
+		 *  -  x = +-Inf (generated by exp())
+		 *  -  x = NaN (spurious inexact exception from y)
+		 */
+		exp_x = exp(x);
+		return cpack(exp_x * cos(y), exp_x * sin(y));
+	}
+}
diff --git a/src/complex/cexpf.c b/src/complex/cexpf.c
new file mode 100644
index 00000000..0cf13a3d
--- /dev/null
+++ b/src/complex/cexpf.c
@@ -0,0 +1,83 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_cexpf.c */
+/*-
+ * Copyright (c) 2011 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libm.h"
+
+static const uint32_t
+exp_ovfl  = 0x42b17218,  /* MAX_EXP * ln2 ~= 88.722839355 */
+cexp_ovfl = 0x43400074;  /* (MAX_EXP - MIN_DENORM_EXP) * ln2 */
+
+float complex cexpf(float complex z)
+{
+	float x, y, exp_x;
+	uint32_t hx, hy;
+
+	x = crealf(z);
+	y = cimagf(z);
+
+	GET_FLOAT_WORD(hy, y);
+	hy &= 0x7fffffff;
+
+	/* cexp(x + I 0) = exp(x) + I 0 */
+	if (hy == 0)
+		return cpackf(expf(x), y);
+	GET_FLOAT_WORD(hx, x);
+	/* cexp(0 + I y) = cos(y) + I sin(y) */
+	if ((hx & 0x7fffffff) == 0)
+		return cpackf(cosf(y), sinf(y));
+
+	if (hy >= 0x7f800000) {
+		if ((hx & 0x7fffffff) != 0x7f800000) {
+			/* cexp(finite|NaN +- I Inf|NaN) = NaN + I NaN */
+			return cpackf(y - y, y - y);
+		} else if (hx & 0x80000000) {
+			/* cexp(-Inf +- I Inf|NaN) = 0 + I 0 */
+			return cpackf(0.0, 0.0);
+		} else {
+			/* cexp(+Inf +- I Inf|NaN) = Inf + I NaN */
+			return cpackf(x, y - y);
+		}
+	}
+
+	if (hx >= exp_ovfl && hx <= cexp_ovfl) {
+		/*
+		 * x is between 88.7 and 192, so we must scale to avoid
+		 * overflow in expf(x).
+		 */
+		return __ldexp_cexpf(z, 0);
+	} else {
+		/*
+		 * Cases covered here:
+		 *  -  x < exp_ovfl and exp(x) won't overflow (common case)
+		 *  -  x > cexp_ovfl, so exp(x) * s overflows for all s > 0
+		 *  -  x = +-Inf (generated by exp())
+		 *  -  x = NaN (spurious inexact exception from y)
+		 */
+		exp_x = expf(x);
+		return cpackf(exp_x * cosf(y), exp_x * sinf(y));
+	}
+}
diff --git a/src/complex/cexpl.c b/src/complex/cexpl.c
new file mode 100644
index 00000000..a27f85c0
--- /dev/null
+++ b/src/complex/cexpl.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+//FIXME
+long double complex cexpl(long double complex z)
+{
+	return cexp(z);
+}
diff --git a/src/complex/cimag.c b/src/complex/cimag.c
new file mode 100644
index 00000000..5e1ad46b
--- /dev/null
+++ b/src/complex/cimag.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+double (cimag)(double complex z)
+{
+	union dcomplex u = {z};
+	return u.a[1];
+}
diff --git a/src/complex/cimagf.c b/src/complex/cimagf.c
new file mode 100644
index 00000000..99fffc58
--- /dev/null
+++ b/src/complex/cimagf.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+float (cimagf)(float complex z)
+{
+	union fcomplex u = {z};
+	return u.a[1];
+}
diff --git a/src/complex/cimagl.c b/src/complex/cimagl.c
new file mode 100644
index 00000000..d9a0780c
--- /dev/null
+++ b/src/complex/cimagl.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+long double (cimagl)(long double complex z)
+{
+	union lcomplex u = {z};
+	return u.a[1];
+}
diff --git a/src/complex/clog.c b/src/complex/clog.c
new file mode 100644
index 00000000..6f10a115
--- /dev/null
+++ b/src/complex/clog.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+// FIXME
+
+/* log(z) = log(|z|) + i arg(z) */
+
+double complex clog(double complex z)
+{
+	double r, phi;
+
+	r = cabs(z);
+	phi = carg(z);
+	return cpack(log(r), phi);
+}
diff --git a/src/complex/clogf.c b/src/complex/clogf.c
new file mode 100644
index 00000000..f3aec54d
--- /dev/null
+++ b/src/complex/clogf.c
@@ -0,0 +1,12 @@
+#include "libm.h"
+
+// FIXME
+
+float complex clogf(float complex z)
+{
+	float r, phi;
+
+	r = cabsf(z);
+	phi = cargf(z);
+	return cpackf(logf(r), phi);
+}
diff --git a/src/complex/clogl.c b/src/complex/clogl.c
new file mode 100644
index 00000000..5b84ba59
--- /dev/null
+++ b/src/complex/clogl.c
@@ -0,0 +1,18 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex clogl(long double complex z)
+{
+	return clog(z);
+}
+#else
+// FIXME
+long double complex clogl(long double complex z)
+{
+	long double r, phi;
+
+	r = cabsl(z);
+	phi = cargl(z);
+	return cpackl(logl(r), phi);
+}
+#endif
diff --git a/src/complex/conj.c b/src/complex/conj.c
new file mode 100644
index 00000000..4aceea7b
--- /dev/null
+++ b/src/complex/conj.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+double complex conj(double complex z)
+{
+	return cpack(creal(z), -cimag(z));
+}
diff --git a/src/complex/conjf.c b/src/complex/conjf.c
new file mode 100644
index 00000000..31556800
--- /dev/null
+++ b/src/complex/conjf.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+float complex conjf(float complex z)
+{
+	return cpackf(crealf(z), -cimagf(z));
+}
diff --git a/src/complex/conjl.c b/src/complex/conjl.c
new file mode 100644
index 00000000..01332262
--- /dev/null
+++ b/src/complex/conjl.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+long double complex conjl(long double complex z)
+{
+	return cpackl(creall(z), -cimagl(z));
+}
diff --git a/src/complex/cpow.c b/src/complex/cpow.c
new file mode 100644
index 00000000..f863588f
--- /dev/null
+++ b/src/complex/cpow.c
@@ -0,0 +1,8 @@
+#include "libm.h"
+
+/* pow(z, c) = exp(c log(z)), See C99 G.6.4.1 */
+
+double complex cpow(double complex z, double complex c)
+{
+	return cexp(c * clog(z));
+}
diff --git a/src/complex/cpowf.c b/src/complex/cpowf.c
new file mode 100644
index 00000000..53c65dcb
--- /dev/null
+++ b/src/complex/cpowf.c
@@ -0,0 +1,6 @@
+#include "libm.h"
+
+float complex cpowf(float complex z, float complex c)
+{
+	return cexpf(c * clogf(z));
+}
diff --git a/src/complex/cpowl.c b/src/complex/cpowl.c
new file mode 100644
index 00000000..c1a80a7b
--- /dev/null
+++ b/src/complex/cpowl.c
@@ -0,0 +1,13 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex cpowl(long double complex z, long double complex c)
+{
+	return cpow(z, c);
+}
+#else
+long double complex cpowl(long double complex z, long double complex c)
+{
+	return cexpl(c * clogl(z));
+}
+#endif
diff --git a/src/complex/cproj.c b/src/complex/cproj.c
new file mode 100644
index 00000000..1cf9bb94
--- /dev/null
+++ b/src/complex/cproj.c
@@ -0,0 +1,8 @@
+#include "libm.h"
+
+double complex cproj(double complex z)
+{
+	if (isinf(creal(z)) || isinf(cimag(z)))
+		return cpack(INFINITY, copysign(0.0, creal(z)));
+	return z;
+}
diff --git a/src/complex/cprojf.c b/src/complex/cprojf.c
new file mode 100644
index 00000000..71129743
--- /dev/null
+++ b/src/complex/cprojf.c
@@ -0,0 +1,8 @@
+#include "libm.h"
+
+float complex cprojf(float complex z)
+{
+	if (isinf(crealf(z)) || isinf(cimagf(z)))
+		return cpackf(INFINITY, copysignf(0.0, crealf(z)));
+	return z;
+}
diff --git a/src/complex/cprojl.c b/src/complex/cprojl.c
new file mode 100644
index 00000000..72e50cf5
--- /dev/null
+++ b/src/complex/cprojl.c
@@ -0,0 +1,15 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex cprojl(long double complex z)
+{
+	return cproj(z);
+}
+#else
+long double complex cprojl(long double complex z)
+{
+	if (isinf(creall(z)) || isinf(cimagl(z)))
+		return cpackl(INFINITY, copysignl(0.0, creall(z)));
+	return z;
+}
+#endif
diff --git a/src/complex/creal.c b/src/complex/creal.c
new file mode 100644
index 00000000..2bb91812
--- /dev/null
+++ b/src/complex/creal.c
@@ -0,0 +1,6 @@
+#include <complex.h>
+
+double creal(double complex z)
+{
+	return z;
+}
diff --git a/src/complex/crealf.c b/src/complex/crealf.c
new file mode 100644
index 00000000..078232f0
--- /dev/null
+++ b/src/complex/crealf.c
@@ -0,0 +1,6 @@
+#include <complex.h>
+
+float crealf(float complex z)
+{
+	return z;
+}
diff --git a/src/complex/creall.c b/src/complex/creall.c
new file mode 100644
index 00000000..56e64097
--- /dev/null
+++ b/src/complex/creall.c
@@ -0,0 +1,6 @@
+#include <complex.h>
+
+long double creall(long double complex z)
+{
+	return z;
+}
diff --git a/src/complex/csin.c b/src/complex/csin.c
new file mode 100644
index 00000000..246a4595
--- /dev/null
+++ b/src/complex/csin.c
@@ -0,0 +1,9 @@
+#include "libm.h"
+
+/* sin(z) = -i sinh(i z) */
+
+double complex csin(double complex z)
+{
+	z = csinh(cpack(-cimag(z), creal(z)));
+	return cpack(cimag(z), -creal(z));
+}
diff --git a/src/complex/csinf.c b/src/complex/csinf.c
new file mode 100644
index 00000000..3aabe8f8
--- /dev/null
+++ b/src/complex/csinf.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+float complex csinf(float complex z)
+{
+	z = csinhf(cpackf(-cimagf(z), crealf(z)));
+	return cpackf(cimagf(z), -crealf(z));
+}
diff --git a/src/complex/csinh.c b/src/complex/csinh.c
new file mode 100644
index 00000000..fe16f06b
--- /dev/null
+++ b/src/complex/csinh.c
@@ -0,0 +1,141 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_csinh.c */
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Hyperbolic sine of a complex argument z = x + i y.
+ *
+ * sinh(z) = sinh(x+iy)
+ *         = sinh(x) cos(y) + i cosh(x) sin(y).
+ *
+ * Exceptional values are noted in the comments within the source code.
+ * These values and the return value were taken from n1124.pdf.
+ */
+
+#include "libm.h"
+
+static const double huge = 0x1p1023;
+
+double complex csinh(double complex z)
+{
+	double x, y, h;
+	int32_t hx, hy, ix, iy, lx, ly;
+
+	x = creal(z);
+	y = cimag(z);
+
+	EXTRACT_WORDS(hx, lx, x);
+	EXTRACT_WORDS(hy, ly, y);
+
+	ix = 0x7fffffff & hx;
+	iy = 0x7fffffff & hy;
+
+	/* Handle the nearly-non-exceptional cases where x and y are finite. */
+	if (ix < 0x7ff00000 && iy < 0x7ff00000) {
+		if ((iy | ly) == 0)
+			return cpack(sinh(x), y);
+		if (ix < 0x40360000)    /* small x: normal case */
+			return cpack(sinh(x) * cos(y), cosh(x) * sin(y));
+
+		/* |x| >= 22, so cosh(x) ~= exp(|x|) */
+		if (ix < 0x40862e42) {
+			/* x < 710: exp(|x|) won't overflow */
+			h = exp(fabs(x)) * 0.5;
+			return cpack(copysign(h, x) * cos(y), h * sin(y));
+		} else if (ix < 0x4096bbaa) {
+			/* x < 1455: scale to avoid overflow */
+			z = __ldexp_cexp(cpack(fabs(x), y), -1);
+			return cpack(creal(z) * copysign(1, x), cimag(z));
+		} else {
+			/* x >= 1455: the result always overflows */
+			h = huge * x;
+			return cpack(h * cos(y), h * h * sin(y));
+		}
+	}
+
+	/*
+	 * sinh(+-0 +- I Inf) = sign(d(+-0, dNaN))0 + I dNaN.
+	 * The sign of 0 in the result is unspecified.  Choice = normally
+	 * the same as dNaN.  Raise the invalid floating-point exception.
+	 *
+	 * sinh(+-0 +- I NaN) = sign(d(+-0, NaN))0 + I d(NaN).
+	 * The sign of 0 in the result is unspecified.  Choice = normally
+	 * the same as d(NaN).
+	 */
+	if ((ix | lx) == 0 && iy >= 0x7ff00000)
+		return cpack(copysign(0, x * (y - y)), y - y);
+
+	/*
+	 * sinh(+-Inf +- I 0) = +-Inf + I +-0.
+	 *
+	 * sinh(NaN +- I 0)   = d(NaN) + I +-0.
+	 */
+	if ((iy | ly) == 0 && ix >= 0x7ff00000) {
+		if (((hx & 0xfffff) | lx) == 0)
+			return cpack(x, y);
+		return cpack(x, copysign(0, y));
+	}
+
+	/*
+	 * sinh(x +- I Inf) = dNaN + I dNaN.
+	 * Raise the invalid floating-point exception for finite nonzero x.
+	 *
+	 * sinh(x + I NaN) = d(NaN) + I d(NaN).
+	 * Optionally raises the invalid floating-point exception for finite
+	 * nonzero x.  Choice = don't raise (except for signaling NaNs).
+	 */
+	if (ix < 0x7ff00000 && iy >= 0x7ff00000)
+		return cpack(y - y, x * (y - y));
+
+	/*
+	 * sinh(+-Inf + I NaN)  = +-Inf + I d(NaN).
+	 * The sign of Inf in the result is unspecified.  Choice = normally
+	 * the same as d(NaN).
+	 *
+	 * sinh(+-Inf +- I Inf) = +Inf + I dNaN.
+	 * The sign of Inf in the result is unspecified.  Choice = always +.
+	 * Raise the invalid floating-point exception.
+	 *
+	 * sinh(+-Inf + I y)   = +-Inf cos(y) + I Inf sin(y)
+	 */
+	if (ix >= 0x7ff00000 && ((hx & 0xfffff) | lx) == 0) {
+		if (iy >= 0x7ff00000)
+			return cpack(x * x, x * (y - y));
+		return cpack(x * cos(y), INFINITY * sin(y));
+	}
+
+	/*
+	 * sinh(NaN + I NaN)  = d(NaN) + I d(NaN).
+	 *
+	 * sinh(NaN +- I Inf) = d(NaN) + I d(NaN).
+	 * Optionally raises the invalid floating-point exception.
+	 * Choice = raise.
+	 *
+	 * sinh(NaN + I y)    = d(NaN) + I d(NaN).
+	 * Optionally raises the invalid floating-point exception for finite
+	 * nonzero y.  Choice = don't raise (except for signaling NaNs).
+	 */
+	return cpack((x * x) * (y - y), (x + x) * (y - y));
+}
diff --git a/src/complex/csinhf.c b/src/complex/csinhf.c
new file mode 100644
index 00000000..bbb116c2
--- /dev/null
+++ b/src/complex/csinhf.c
@@ -0,0 +1,90 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_csinhf.c */
+/*-
+ * Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Hyperbolic sine of a complex argument z.  See s_csinh.c for details.
+ */
+
+#include "libm.h"
+
+static const float huge = 0x1p127;
+
+float complex csinhf(float complex z)
+{
+	float x, y, h;
+	int32_t hx, hy, ix, iy;
+
+	x = crealf(z);
+	y = cimagf(z);
+
+	GET_FLOAT_WORD(hx, x);
+	GET_FLOAT_WORD(hy, y);
+
+	ix = 0x7fffffff & hx;
+	iy = 0x7fffffff & hy;
+
+	if (ix < 0x7f800000 && iy < 0x7f800000) {
+		if (iy == 0)
+			return cpackf(sinhf(x), y);
+		if (ix < 0x41100000)    /* small x: normal case */
+			return cpackf(sinhf(x) * cosf(y), coshf(x) * sinf(y));
+
+		/* |x| >= 9, so cosh(x) ~= exp(|x|) */
+		if (ix < 0x42b17218) {
+			/* x < 88.7: expf(|x|) won't overflow */
+			h = expf(fabsf(x)) * 0.5f;
+			return cpackf(copysignf(h, x) * cosf(y), h * sinf(y));
+		} else if (ix < 0x4340b1e7) {
+			/* x < 192.7: scale to avoid overflow */
+			z = __ldexp_cexpf(cpackf(fabsf(x), y), -1);
+			return cpackf(crealf(z) * copysignf(1, x), cimagf(z));
+		} else {
+			/* x >= 192.7: the result always overflows */
+			h = huge * x;
+			return cpackf(h * cosf(y), h * h * sinf(y));
+		}
+	}
+
+	if (ix == 0 && iy >= 0x7f800000)
+		return cpackf(copysignf(0, x * (y - y)), y - y);
+
+	if (iy == 0 && ix >= 0x7f800000) {
+		if ((hx & 0x7fffff) == 0)
+			return cpackf(x, y);
+		return cpackf(x, copysignf(0, y));
+	}
+
+	if (ix < 0x7f800000 && iy >= 0x7f800000)
+		return cpackf(y - y, x * (y - y));
+
+	if (ix >= 0x7f800000 && (hx & 0x7fffff) == 0) {
+		if (iy >= 0x7f800000)
+			return cpackf(x * x, x * (y - y));
+		return cpackf(x * cosf(y), INFINITY * sinf(y));
+	}
+
+	return cpackf((x * x) * (y - y), (x + x) * (y - y));
+}
diff --git a/src/complex/csinhl.c b/src/complex/csinhl.c
new file mode 100644
index 00000000..c566653b
--- /dev/null
+++ b/src/complex/csinhl.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+//FIXME
+long double complex csinhl(long double complex z)
+{
+	return csinh(z);
+}
diff --git a/src/complex/csinl.c b/src/complex/csinl.c
new file mode 100644
index 00000000..4ad86745
--- /dev/null
+++ b/src/complex/csinl.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex csinl(long double complex z)
+{
+	return csin(z);
+}
+#else
+long double complex csinl(long double complex z)
+{
+	z = csinhl(cpackl(-cimagl(z), creall(z)));
+	return cpackl(cimagl(z), -creall(z));
+}
+#endif
diff --git a/src/complex/csqrt.c b/src/complex/csqrt.c
new file mode 100644
index 00000000..21fb879d
--- /dev/null
+++ b/src/complex/csqrt.c
@@ -0,0 +1,100 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrt.c */
+/*-
+ * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libm.h"
+
+/*
+ * gcc doesn't implement complex multiplication or division correctly,
+ * so we need to handle infinities specially. We turn on this pragma to
+ * notify conforming c99 compilers that the fast-but-incorrect code that
+ * gcc generates is acceptable, since the special cases have already been
+ * handled.
+ */
+#pragma STDC CX_LIMITED_RANGE ON
+
+/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */
+#define THRESH  0x1.a827999fcef32p+1022
+
+double complex csqrt(double complex z)
+{
+	double complex result;
+	double a, b;
+	double t;
+	int scale;
+
+	a = creal(z);
+	b = cimag(z);
+
+	/* Handle special cases. */
+	if (z == 0)
+		return cpack(0, b);
+	if (isinf(b))
+		return cpack(INFINITY, b);
+	if (isnan(a)) {
+		t = (b - b) / (b - b);  /* raise invalid if b is not a NaN */
+		return cpack(a, t);   /* return NaN + NaN i */
+	}
+	if (isinf(a)) {
+		/*
+		 * csqrt(inf + NaN i)  = inf +  NaN i
+		 * csqrt(inf + y i)    = inf +  0 i
+		 * csqrt(-inf + NaN i) = NaN +- inf i
+		 * csqrt(-inf + y i)   = 0   +  inf i
+		 */
+		if (signbit(a))
+			return cpack(fabs(b - b), copysign(a, b));
+		else
+			return cpack(a, copysign(b - b, b));
+	}
+	/*
+	 * The remaining special case (b is NaN) is handled just fine by
+	 * the normal code path below.
+	 */
+
+	/* Scale to avoid overflow. */
+	if (fabs(a) >= THRESH || fabs(b) >= THRESH) {
+		a *= 0.25;
+		b *= 0.25;
+		scale = 1;
+	} else {
+		scale = 0;
+	}
+
+	/* Algorithm 312, CACM vol 10, Oct 1967. */
+	if (a >= 0) {
+		t = sqrt((a + hypot(a, b)) * 0.5);
+		result = cpack(t, b / (2 * t));
+	} else {
+		t = sqrt((-a + hypot(a, b)) * 0.5);
+		result = cpack(fabs(b) / (2 * t), copysign(t, b));
+	}
+
+	/* Rescale. */
+	if (scale)
+		result *= 2;
+	return result;
+}
diff --git a/src/complex/csqrtf.c b/src/complex/csqrtf.c
new file mode 100644
index 00000000..16487c23
--- /dev/null
+++ b/src/complex/csqrtf.c
@@ -0,0 +1,82 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_csqrtf.c */
+/*-
+ * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "libm.h"
+
+/*
+ * gcc doesn't implement complex multiplication or division correctly,
+ * so we need to handle infinities specially. We turn on this pragma to
+ * notify conforming c99 compilers that the fast-but-incorrect code that
+ * gcc generates is acceptable, since the special cases have already been
+ * handled.
+ */
+#pragma STDC CX_LIMITED_RANGE ON
+
+float complex csqrtf(float complex z)
+{
+	float a = crealf(z), b = cimagf(z);
+	double t;
+
+	/* Handle special cases. */
+	if (z == 0)
+		return cpackf(0, b);
+	if (isinf(b))
+		return cpackf(INFINITY, b);
+	if (isnan(a)) {
+		t = (b - b) / (b - b);  /* raise invalid if b is not a NaN */
+		return cpackf(a, t);  /* return NaN + NaN i */
+	}
+	if (isinf(a)) {
+		/*
+		 * csqrtf(inf + NaN i)  = inf +  NaN i
+		 * csqrtf(inf + y i)    = inf +  0 i
+		 * csqrtf(-inf + NaN i) = NaN +- inf i
+		 * csqrtf(-inf + y i)   = 0   +  inf i
+		 */
+		if (signbit(a))
+			return cpackf(fabsf(b - b), copysignf(a, b));
+		else
+			return cpackf(a, copysignf(b - b, b));
+	}
+	/*
+	 * The remaining special case (b is NaN) is handled just fine by
+	 * the normal code path below.
+	 */
+
+	/*
+	 * We compute t in double precision to avoid overflow and to
+	 * provide correct rounding in nearly all cases.
+	 * This is Algorithm 312, CACM vol 10, Oct 1967.
+	 */
+	if (a >= 0) {
+		t = sqrt((a + hypot(a, b)) * 0.5);
+		return cpackf(t, b / (2.0 * t));
+	} else {
+		t = sqrt((-a + hypot(a, b)) * 0.5);
+		return cpackf(fabsf(b) / (2.0 * t), copysignf(t, b));
+	}
+}
diff --git a/src/complex/csqrtl.c b/src/complex/csqrtl.c
new file mode 100644
index 00000000..0600ef3b
--- /dev/null
+++ b/src/complex/csqrtl.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+//FIXME
+long double complex csqrtl(long double complex z)
+{
+	return csqrt(z);
+}
diff --git a/src/complex/ctan.c b/src/complex/ctan.c
new file mode 100644
index 00000000..4741a4df
--- /dev/null
+++ b/src/complex/ctan.c
@@ -0,0 +1,9 @@
+#include "libm.h"
+
+/* tan(z) = -i tanh(i z) */
+
+double complex ctan(double complex z)
+{
+	z = ctanh(cpack(-cimag(z), creal(z)));
+	return cpack(cimag(z), -creal(z));
+}
diff --git a/src/complex/ctanf.c b/src/complex/ctanf.c
new file mode 100644
index 00000000..9bbeb051
--- /dev/null
+++ b/src/complex/ctanf.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+float complex ctanf(float complex z)
+{
+	z = ctanhf(cpackf(-cimagf(z), crealf(z)));
+	return cpackf(cimagf(z), -crealf(z));
+}
diff --git a/src/complex/ctanh.c b/src/complex/ctanh.c
new file mode 100644
index 00000000..dd569fc3
--- /dev/null
+++ b/src/complex/ctanh.c
@@ -0,0 +1,127 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */
+/*-
+ * Copyright (c) 2011 David Schultz
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Hyperbolic tangent of a complex argument z = x + i y.
+ *
+ * The algorithm is from:
+ *
+ *   W. Kahan.  Branch Cuts for Complex Elementary Functions or Much
+ *   Ado About Nothing's Sign Bit.  In The State of the Art in
+ *   Numerical Analysis, pp. 165 ff.  Iserles and Powell, eds., 1987.
+ *
+ * Method:
+ *
+ *   Let t    = tan(x)
+ *       beta = 1/cos^2(y)
+ *       s    = sinh(x)
+ *       rho  = cosh(x)
+ *
+ *   We have:
+ *
+ *   tanh(z) = sinh(z) / cosh(z)
+ *
+ *             sinh(x) cos(y) + i cosh(x) sin(y)
+ *           = ---------------------------------
+ *             cosh(x) cos(y) + i sinh(x) sin(y)
+ *
+ *             cosh(x) sinh(x) / cos^2(y) + i tan(y)
+ *           = -------------------------------------
+ *                    1 + sinh^2(x) / cos^2(y)
+ *
+ *             beta rho s + i t
+ *           = ----------------
+ *               1 + beta s^2
+ *
+ * Modifications:
+ *
+ *   I omitted the original algorithm's handling of overflow in tan(x) after
+ *   verifying with nearpi.c that this can't happen in IEEE single or double
+ *   precision.  I also handle large x differently.
+ */
+
+#include "libm.h"
+
+double complex ctanh(double complex z)
+{
+	double x, y;
+	double t, beta, s, rho, denom;
+	uint32_t hx, ix, lx;
+
+	x = creal(z);
+	y = cimag(z);
+
+	EXTRACT_WORDS(hx, lx, x);
+	ix = hx & 0x7fffffff;
+
+	/*
+	 * ctanh(NaN + i 0) = NaN + i 0
+	 *
+	 * ctanh(NaN + i y) = NaN + i NaN               for y != 0
+	 *
+	 * The imaginary part has the sign of x*sin(2*y), but there's no
+	 * special effort to get this right.
+	 *
+	 * ctanh(+-Inf +- i Inf) = +-1 +- 0
+	 *
+	 * ctanh(+-Inf + i y) = +-1 + 0 sin(2y)         for y finite
+	 *
+	 * The imaginary part of the sign is unspecified.  This special
+	 * case is only needed to avoid a spurious invalid exception when
+	 * y is infinite.
+	 */
+	if (ix >= 0x7ff00000) {
+		if ((ix & 0xfffff) | lx)        /* x is NaN */
+			return cpack(x, (y == 0 ? y : x * y));
+		SET_HIGH_WORD(x, hx - 0x40000000);      /* x = copysign(1, x) */
+		return cpack(x, copysign(0, isinf(y) ? y : sin(y) * cos(y)));
+	}
+
+	/*
+	 * ctanh(x + i NAN) = NaN + i NaN
+	 * ctanh(x +- i Inf) = NaN + i NaN
+	 */
+	if (!isfinite(y))
+		return cpack(y - y, y - y);
+
+	/*
+	 * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the
+	 * approximation sinh^2(huge) ~= exp(2*huge) / 4.
+	 * We use a modified formula to avoid spurious overflow.
+	 */
+	if (ix >= 0x40360000) { /* x >= 22 */
+		double exp_mx = exp(-fabs(x));
+		return cpack(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_mx);
+	}
+
+	/* Kahan's algorithm */
+	t = tan(y);
+	beta = 1.0 + t * t;     /* = 1 / cos^2(y) */
+	s = sinh(x);
+	rho = sqrt(1 + s * s);  /* = cosh(x) */
+	denom = 1 + beta * s * s;
+	return cpack((beta * rho * s) / denom, t / denom);
+}
diff --git a/src/complex/ctanhf.c b/src/complex/ctanhf.c
new file mode 100644
index 00000000..7d746134
--- /dev/null
+++ b/src/complex/ctanhf.c
@@ -0,0 +1,66 @@
+/* origin: FreeBSD /usr/src/lib/msun/src/s_ctanhf.c */
+/*-
+ * Copyright (c) 2011 David Schultz
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Hyperbolic tangent of a complex argument z.  See s_ctanh.c for details.
+ */
+
+#include "libm.h"
+
+float complex ctanhf(float complex z)
+{
+	float x, y;
+	float t, beta, s, rho, denom;
+	uint32_t hx, ix;
+
+	x = crealf(z);
+	y = cimagf(z);
+
+	GET_FLOAT_WORD(hx, x);
+	ix = hx & 0x7fffffff;
+
+	if (ix >= 0x7f800000) {
+		if (ix & 0x7fffff)
+			return cpackf(x, (y == 0 ? y : x * y));
+		SET_FLOAT_WORD(x, hx - 0x40000000);
+		return cpackf(x, copysignf(0, isinf(y) ? y : sinf(y) * cosf(y)));
+	}
+
+	if (!isfinite(y))
+		return cpackf(y - y, y - y);
+
+	if (ix >= 0x41300000) { /* x >= 11 */
+		float exp_mx = expf(-fabsf(x));
+		return cpackf(copysignf(1, x), 4 * sinf(y) * cosf(y) * exp_mx * exp_mx);
+	}
+
+	t = tanf(y);
+	beta = 1.0 + t * t;
+	s = sinhf(x);
+	rho = sqrtf(1 + s * s);
+	denom = 1 + beta * s * s;
+	return cpackf((beta * rho * s) / denom, t / denom);
+}
diff --git a/src/complex/ctanhl.c b/src/complex/ctanhl.c
new file mode 100644
index 00000000..89a75d13
--- /dev/null
+++ b/src/complex/ctanhl.c
@@ -0,0 +1,7 @@
+#include "libm.h"
+
+//FIXME
+long double complex ctanhl(long double complex z)
+{
+	return ctanh(z);
+}
diff --git a/src/complex/ctanl.c b/src/complex/ctanl.c
new file mode 100644
index 00000000..4b4c99b6
--- /dev/null
+++ b/src/complex/ctanl.c
@@ -0,0 +1,14 @@
+#include "libm.h"
+
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+long double complex ctanl(long double complex z)
+{
+	return ctan(z);
+}
+#else
+long double complex ctanl(long double complex z)
+{
+	z = ctanhl(cpackl(-cimagl(z), creall(z)));
+	return cpackl(cimagl(z), -creall(z));
+}
+#endif