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