xref: /freebsd/lib/msun/src/s_csqrt.c (revision 0dd5a5603e7a33d976f8e6015620bbc79839c609)
1aaf70b23SDavid Schultz /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
4aaf70b23SDavid Schultz  * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
5aaf70b23SDavid Schultz  * All rights reserved.
6aaf70b23SDavid Schultz  *
7aaf70b23SDavid Schultz  * Redistribution and use in source and binary forms, with or without
8aaf70b23SDavid Schultz  * modification, are permitted provided that the following conditions
9aaf70b23SDavid Schultz  * are met:
10aaf70b23SDavid Schultz  * 1. Redistributions of source code must retain the above copyright
11aaf70b23SDavid Schultz  *    notice, this list of conditions and the following disclaimer.
12aaf70b23SDavid Schultz  * 2. Redistributions in binary form must reproduce the above copyright
13aaf70b23SDavid Schultz  *    notice, this list of conditions and the following disclaimer in the
14aaf70b23SDavid Schultz  *    documentation and/or other materials provided with the distribution.
15aaf70b23SDavid Schultz  *
16aaf70b23SDavid Schultz  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17aaf70b23SDavid Schultz  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18aaf70b23SDavid Schultz  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19aaf70b23SDavid Schultz  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20aaf70b23SDavid Schultz  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21aaf70b23SDavid Schultz  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22aaf70b23SDavid Schultz  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23aaf70b23SDavid Schultz  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24aaf70b23SDavid Schultz  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25aaf70b23SDavid Schultz  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26aaf70b23SDavid Schultz  * SUCH DAMAGE.
27aaf70b23SDavid Schultz  */
28aaf70b23SDavid Schultz 
29aaf70b23SDavid Schultz #include <complex.h>
30511dd36bSDavid Schultz #include <float.h>
31aaf70b23SDavid Schultz #include <math.h>
32aaf70b23SDavid Schultz 
33aaf70b23SDavid Schultz #include "math_private.h"
34aaf70b23SDavid Schultz 
351693fd03SBruce Evans /* For avoiding overflow for components >= DBL_MAX / (1 + sqrt(2)). */
36aaf70b23SDavid Schultz #define	THRESH	0x1.a827999fcef32p+1022
37aaf70b23SDavid Schultz 
38aaf70b23SDavid Schultz double complex
csqrt(double complex z)39aaf70b23SDavid Schultz csqrt(double complex z)
40aaf70b23SDavid Schultz {
41aaf70b23SDavid Schultz 	double complex result;
429d7dc136SBruce Evans 	double a, b, rx, ry, scale, t;
43aaf70b23SDavid Schultz 
4473b2958bSDavid Schultz 	a = creal(z);
4573b2958bSDavid Schultz 	b = cimag(z);
4673b2958bSDavid Schultz 
47aaf70b23SDavid Schultz 	/* Handle special cases. */
48aaf70b23SDavid Schultz 	if (z == 0)
492cec876aSEd Schouten 		return (CMPLX(0, b));
50aaf70b23SDavid Schultz 	if (isinf(b))
512cec876aSEd Schouten 		return (CMPLX(INFINITY, b));
52aaf70b23SDavid Schultz 	if (isnan(a)) {
53aaf70b23SDavid Schultz 		t = (b - b) / (b - b);	/* raise invalid if b is not a NaN */
546f1b8a07SBruce Evans 		return (CMPLX(a + 0.0L + t, a + 0.0L + t)); /* NaN + NaN i */
55aaf70b23SDavid Schultz 	}
56aaf70b23SDavid Schultz 	if (isinf(a)) {
57aaf70b23SDavid Schultz 		/*
5873b2958bSDavid Schultz 		 * csqrt(inf + NaN i)  = inf +  NaN i
59aaf70b23SDavid Schultz 		 * csqrt(inf + y i)    = inf +  0 i
6073b2958bSDavid Schultz 		 * csqrt(-inf + NaN i) = NaN +- inf i
61aaf70b23SDavid Schultz 		 * csqrt(-inf + y i)   = 0   +  inf i
62aaf70b23SDavid Schultz 		 */
63aaf70b23SDavid Schultz 		if (signbit(a))
642cec876aSEd Schouten 			return (CMPLX(fabs(b - b), copysign(a, b)));
65aaf70b23SDavid Schultz 		else
662cec876aSEd Schouten 			return (CMPLX(a, copysign(b - b, b)));
67aaf70b23SDavid Schultz 	}
686f1b8a07SBruce Evans 	if (isnan(b)) {
696f1b8a07SBruce Evans 		t = (a - a) / (a - a);	/* raise invalid */
706f1b8a07SBruce Evans 		return (CMPLX(b + 0.0L + t, b + 0.0L + t)); /* NaN + NaN i */
716f1b8a07SBruce Evans 	}
72aaf70b23SDavid Schultz 
73aaf70b23SDavid Schultz 	/* Scale to avoid overflow. */
7473b2958bSDavid Schultz 	if (fabs(a) >= THRESH || fabs(b) >= THRESH) {
759d7dc136SBruce Evans 		/*
769d7dc136SBruce Evans 		 * Don't scale a or b if this might give (spurious)
779d7dc136SBruce Evans 		 * underflow.  Then the unscaled value is an equivalent
789d7dc136SBruce Evans 		 * infinitesmal (or 0).
799d7dc136SBruce Evans 		 */
809d7dc136SBruce Evans 		if (fabs(a) >= 0x1p-1020)
81aaf70b23SDavid Schultz 			a *= 0.25;
829d7dc136SBruce Evans 		if (fabs(b) >= 0x1p-1020)
83aaf70b23SDavid Schultz 			b *= 0.25;
849d7dc136SBruce Evans 		scale = 2;
85aaf70b23SDavid Schultz 	} else {
869d7dc136SBruce Evans 		scale = 1;
879d7dc136SBruce Evans 	}
889d7dc136SBruce Evans 
899d7dc136SBruce Evans 	/* Scale to reduce inaccuracies when both components are denormal. */
909d7dc136SBruce Evans 	if (fabs(a) < 0x1p-1022 && fabs(b) < 0x1p-1022) {
919d7dc136SBruce Evans 		a *= 0x1p54;
929d7dc136SBruce Evans 		b *= 0x1p54;
939d7dc136SBruce Evans 		scale = 0x1p-27;
94aaf70b23SDavid Schultz 	}
95aaf70b23SDavid Schultz 
9673b2958bSDavid Schultz 	/* Algorithm 312, CACM vol 10, Oct 1967. */
97aaf70b23SDavid Schultz 	if (a >= 0) {
98aaf70b23SDavid Schultz 		t = sqrt((a + hypot(a, b)) * 0.5);
99b7092eefSBruce Evans 		rx = scale * t;
100b7092eefSBruce Evans 		ry = scale * b / (2 * t);
101aaf70b23SDavid Schultz 	} else {
102aaf70b23SDavid Schultz 		t = sqrt((-a + hypot(a, b)) * 0.5);
103b7092eefSBruce Evans 		rx = scale * fabs(b) / (2 * t);
104b7092eefSBruce Evans 		ry = copysign(scale * t, b);
105aaf70b23SDavid Schultz 	}
106aaf70b23SDavid Schultz 
107b7092eefSBruce Evans 	return (CMPLX(rx, ry));
108aaf70b23SDavid Schultz }
109511dd36bSDavid Schultz 
110511dd36bSDavid Schultz #if LDBL_MANT_DIG == 53
111511dd36bSDavid Schultz __weak_reference(csqrt, csqrtl);
112511dd36bSDavid Schultz #endif
113