1174617Sdas/*-
2174617Sdas * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
3174617Sdas * All rights reserved.
4174617Sdas *
5174617Sdas * Redistribution and use in source and binary forms, with or without
6174617Sdas * modification, are permitted provided that the following conditions
7174617Sdas * are met:
8174617Sdas * 1. Redistributions of source code must retain the above copyright
9174617Sdas *    notice, this list of conditions and the following disclaimer.
10174617Sdas * 2. Redistributions in binary form must reproduce the above copyright
11174617Sdas *    notice, this list of conditions and the following disclaimer in the
12174617Sdas *    documentation and/or other materials provided with the distribution.
13174617Sdas *
14174617Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15174617Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16174617Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17174617Sdas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18174617Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19174617Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20174617Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21174617Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22174617Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23174617Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24174617Sdas * SUCH DAMAGE.
25174617Sdas */
26174617Sdas
27174617Sdas#include <sys/cdefs.h>
28174617Sdas__FBSDID("$FreeBSD$");
29174617Sdas
30174617Sdas#include <complex.h>
31177761Sdas#include <float.h>
32174617Sdas#include <math.h>
33174617Sdas
34174617Sdas#include "math_private.h"
35174617Sdas
36174617Sdas/*
37174617Sdas * gcc doesn't implement complex multiplication or division correctly,
38174617Sdas * so we need to handle infinities specially. We turn on this pragma to
39174617Sdas * notify conforming c99 compilers that the fast-but-incorrect code that
40174617Sdas * gcc generates is acceptable, since the special cases have already been
41174617Sdas * handled.
42174617Sdas */
43181402Sdas#pragma	STDC CX_LIMITED_RANGE	ON
44174617Sdas
45175225Sdas/* We risk spurious overflow for components >= DBL_MAX / (1 + sqrt(2)). */
46175225Sdas#define	THRESH	0x1.a827999fcef32p+1022
47174617Sdas
48174617Sdasdouble complex
49174617Sdascsqrt(double complex z)
50174617Sdas{
51175225Sdas	double complex result;
52175225Sdas	double a, b;
53174617Sdas	double t;
54174617Sdas	int scale;
55174617Sdas
56175225Sdas	a = creal(z);
57175225Sdas	b = cimag(z);
58175225Sdas
59174617Sdas	/* Handle special cases. */
60174617Sdas	if (z == 0)
61174617Sdas		return (cpack(0, b));
62174617Sdas	if (isinf(b))
63174617Sdas		return (cpack(INFINITY, b));
64174617Sdas	if (isnan(a)) {
65174617Sdas		t = (b - b) / (b - b);	/* raise invalid if b is not a NaN */
66175225Sdas		return (cpack(a, t));	/* return NaN + NaN i */
67174617Sdas	}
68174617Sdas	if (isinf(a)) {
69174617Sdas		/*
70175225Sdas		 * csqrt(inf + NaN i)  = inf +  NaN i
71174617Sdas		 * csqrt(inf + y i)    = inf +  0 i
72175225Sdas		 * csqrt(-inf + NaN i) = NaN +- inf i
73174617Sdas		 * csqrt(-inf + y i)   = 0   +  inf i
74174617Sdas		 */
75174617Sdas		if (signbit(a))
76174617Sdas			return (cpack(fabs(b - b), copysign(a, b)));
77174617Sdas		else
78174617Sdas			return (cpack(a, copysign(b - b, b)));
79174617Sdas	}
80174617Sdas	/*
81174617Sdas	 * The remaining special case (b is NaN) is handled just fine by
82174617Sdas	 * the normal code path below.
83174617Sdas	 */
84174617Sdas
85174617Sdas	/* Scale to avoid overflow. */
86175225Sdas	if (fabs(a) >= THRESH || fabs(b) >= THRESH) {
87175225Sdas		a *= 0.25;
88175225Sdas		b *= 0.25;
89175225Sdas		scale = 1;
90174617Sdas	} else {
91175225Sdas		scale = 0;
92174617Sdas	}
93174617Sdas
94175225Sdas	/* Algorithm 312, CACM vol 10, Oct 1967. */
95174617Sdas	if (a >= 0) {
96174617Sdas		t = sqrt((a + hypot(a, b)) * 0.5);
97174617Sdas		result = cpack(t, b / (2 * t));
98174617Sdas	} else {
99174617Sdas		t = sqrt((-a + hypot(a, b)) * 0.5);
100174617Sdas		result = cpack(fabs(b) / (2 * t), copysign(t, b));
101174617Sdas	}
102174617Sdas
103175225Sdas	/* Rescale. */
104174617Sdas	if (scale)
105175225Sdas		return (result * 2);
106174617Sdas	else
107175225Sdas		return (result);
108174617Sdas}
109177761Sdas
110177761Sdas#if LDBL_MANT_DIG == 53
111177761Sdas__weak_reference(csqrt, csqrtl);
112177761Sdas#endif
113