xref: /openbsd-src/lib/libm/src/s_csqrtl.c (revision 2f2c00629eff6a304ebffb255fc56f4fa7a1833b)
1*2f2c0062Sguenther /*	$OpenBSD: s_csqrtl.c,v 1.4 2016/09/12 19:47:02 guenther Exp $	*/
2de3697aaSmartynas 
3de3697aaSmartynas /*
4de3697aaSmartynas  * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
5de3697aaSmartynas  *
6de3697aaSmartynas  * Permission to use, copy, modify, and distribute this software for any
7de3697aaSmartynas  * purpose with or without fee is hereby granted, provided that the above
8de3697aaSmartynas  * copyright notice and this permission notice appear in all copies.
9de3697aaSmartynas  *
10de3697aaSmartynas  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11de3697aaSmartynas  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12de3697aaSmartynas  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13de3697aaSmartynas  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14de3697aaSmartynas  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15de3697aaSmartynas  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16de3697aaSmartynas  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17de3697aaSmartynas  */
18de3697aaSmartynas 
19de3697aaSmartynas /*							csqrtl()
20de3697aaSmartynas  *
21de3697aaSmartynas  *	Complex square root
22de3697aaSmartynas  *
23de3697aaSmartynas  *
24de3697aaSmartynas  *
25de3697aaSmartynas  * SYNOPSIS:
26de3697aaSmartynas  *
27de3697aaSmartynas  * long double complex csqrtl();
28de3697aaSmartynas  * long double complex z, w;
29de3697aaSmartynas  *
30de3697aaSmartynas  * w = csqrtl( z );
31de3697aaSmartynas  *
32de3697aaSmartynas  *
33de3697aaSmartynas  *
34de3697aaSmartynas  * DESCRIPTION:
35de3697aaSmartynas  *
36de3697aaSmartynas  *
37de3697aaSmartynas  * If z = x + iy,  r = |z|, then
38de3697aaSmartynas  *
39de3697aaSmartynas  *                       1/2
40de3697aaSmartynas  * Re w  =  [ (r + x)/2 ]   ,
41de3697aaSmartynas  *
42de3697aaSmartynas  *                       1/2
43de3697aaSmartynas  * Im w  =  [ (r - x)/2 ]   .
44de3697aaSmartynas  *
45de3697aaSmartynas  * Cancellation error in r-x or r+x is avoided by using the
46de3697aaSmartynas  * identity  2 Re w Im w  =  y.
47de3697aaSmartynas  *
48de3697aaSmartynas  * Note that -w is also a square root of z.  The root chosen
49de3697aaSmartynas  * is always in the right half plane and Im w has the same sign as y.
50de3697aaSmartynas  *
51de3697aaSmartynas  *
52de3697aaSmartynas  *
53de3697aaSmartynas  * ACCURACY:
54de3697aaSmartynas  *
55de3697aaSmartynas  *                      Relative error:
56de3697aaSmartynas  * arithmetic   domain     # trials      peak         rms
57de3697aaSmartynas  *    IEEE      -10,+10     500000      1.1e-19     3.0e-20
58de3697aaSmartynas  *
59de3697aaSmartynas  */
60de3697aaSmartynas 
61de3697aaSmartynas #include <complex.h>
62de3697aaSmartynas #include <math.h>
63de3697aaSmartynas 
64de3697aaSmartynas long double complex
csqrtl(long double complex z)65de3697aaSmartynas csqrtl(long double complex z)
66de3697aaSmartynas {
67de3697aaSmartynas 	long double complex w;
68de3697aaSmartynas 	long double x, y, r, t, scale;
69de3697aaSmartynas 
70c18f5b07Smartynas 	x = creall(z);
71c18f5b07Smartynas 	y = cimagl(z);
72de3697aaSmartynas 
73de3697aaSmartynas 	if (y == 0.0L) {
74de3697aaSmartynas 		if (x < 0.0L) {
75d9937d2cSshadchin 			w = 0.0L + copysign(sqrtl(-x), y) * I;
76de3697aaSmartynas 			return (w);
77de3697aaSmartynas 		}
78de3697aaSmartynas 		else {
79de3697aaSmartynas 			w = sqrtl(x) + 0.0L * I;
80de3697aaSmartynas 			return (w);
81de3697aaSmartynas 		}
82de3697aaSmartynas 	}
83de3697aaSmartynas 
84de3697aaSmartynas 	if (x == 0.0L) {
85de3697aaSmartynas 		r = fabsl(y);
86de3697aaSmartynas 		r = sqrtl(0.5L * r);
87de3697aaSmartynas 		if (y > 0.0L)
88de3697aaSmartynas 			w = r + r * I;
89de3697aaSmartynas 		else
90de3697aaSmartynas 			w = r - r * I;
91de3697aaSmartynas 		return (w);
92de3697aaSmartynas 	}
93de3697aaSmartynas 
94de3697aaSmartynas 	/* Rescale to avoid internal overflow or underflow.  */
95de3697aaSmartynas 	if ((fabsl(x) > 4.0L) || (fabsl(y) > 4.0L)) {
96de3697aaSmartynas 		x *= 0.25L;
97de3697aaSmartynas 		y *= 0.25L;
98de3697aaSmartynas 		scale = 2.0L;
99de3697aaSmartynas 	}
100de3697aaSmartynas 	else {
101de3697aaSmartynas #if 1
102de3697aaSmartynas 		x *= 7.3786976294838206464e19;  /* 2^66 */
103de3697aaSmartynas 		y *= 7.3786976294838206464e19;
104de3697aaSmartynas 		scale = 1.16415321826934814453125e-10;  /* 2^-33 */
105de3697aaSmartynas #else
106de3697aaSmartynas 		x *= 4.0L;
107de3697aaSmartynas 		y *= 4.0L;
108de3697aaSmartynas 		scale = 0.5L;
109de3697aaSmartynas #endif
110de3697aaSmartynas 	}
111de3697aaSmartynas 	w = x + y * I;
112de3697aaSmartynas 	r = cabsl(w);
113de3697aaSmartynas 	if (x > 0) {
114de3697aaSmartynas 		t = sqrtl(0.5L * r + 0.5L * x);
115de3697aaSmartynas 		r = scale * fabsl((0.5L * y) / t);
116de3697aaSmartynas 		t *= scale;
117de3697aaSmartynas 	}
118de3697aaSmartynas 	else {
119de3697aaSmartynas 		r = sqrtl(0.5L * r - 0.5L * x);
120de3697aaSmartynas 		t = scale * fabsl((0.5L * y) / r);
121de3697aaSmartynas 		r *= scale;
122de3697aaSmartynas 	}
123de3697aaSmartynas 	if (y < 0)
124de3697aaSmartynas 		w = t - r * I;
125de3697aaSmartynas 	else
126de3697aaSmartynas 		w = t + r * I;
127de3697aaSmartynas 	return (w);
128de3697aaSmartynas }
129*2f2c0062Sguenther DEF_STD(csqrtl);
130