1 /**
2  * A complex number implementation
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   public domain
8  * License:     public domain
9  * Source:      $(DMDSRC backend/_bcomplex.d)
10  */
11 
12 module dmd.backend.bcomplex;
13 
14 public import dmd.root.longdouble : targ_ldouble = longdouble;
15 import core.stdc.math : fabs, fabsl, sqrt;
16 version(CRuntime_Microsoft)
17     private import dmd.root.longdouble : fabsl, sqrt; // needed if longdouble is longdouble_soft
18 
19 @nogc:
20 @safe:
21 nothrow:
22 
23 // Roll our own for reliable bootstrapping
24 
25 
26 struct Complex_f
27 {
28 nothrow:
29     float re, im;
30 
31     static Complex_f div(ref Complex_f x, ref Complex_f y)
32     {
33         if (fabs(y.re) < fabs(y.im))
34         {
35             const r = y.re / y.im;
36             const den = y.im + r * y.re;
37             return Complex_f(cast(float)((x.re * r + x.im) / den),
38                              cast(float)((x.im * r - x.re) / den));
39         }
40         else
41         {
42             const r = y.im / y.re;
43             const den = y.re + r * y.im;
44             return Complex_f(cast(float)((x.re + r * x.im) / den),
45                              cast(float)((x.im - r * x.re) / den));
46         }
47     }
48 
49     static Complex_f mul(ref Complex_f x, ref Complex_f y) pure
50     {
51         return Complex_f(x.re * y.re - x.im * y.im,
52                          x.im * y.re + x.re * y.im);
53     }
54 
55     static targ_ldouble abs(ref Complex_f z)
56     {
57         const targ_ldouble x = fabs(z.re);
58         const targ_ldouble y = fabs(z.im);
59         if (x == 0)
60             return y;
61         else if (y == 0)
62             return x;
63         else if (x > y)
64         {
65             const targ_ldouble temp = y / x;
66             return x * sqrt(1 + temp * temp);
67         }
68         else
69         {
70             const targ_ldouble temp = x / y;
71             return y * sqrt(1 + temp * temp);
72         }
73     }
74 
75     static Complex_f sqrtc(ref Complex_f z)
76     {
77         if (z.re == 0 && z.im == 0)
78         {
79             return Complex_f(0, 0);
80         }
81         else
82         {
83             const targ_ldouble x = fabs(z.re);
84             const targ_ldouble y = fabs(z.im);
85             targ_ldouble r, w;
86             if (x >= y)
87             {
88                 r = y / x;
89                 w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
90             }
91             else
92             {
93                 r = x / y;
94                 w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
95             }
96 
97             if (z.re >= 0)
98             {
99                 return Complex_f(cast(float)w, (z.im / cast(float)(w + w)));
100             }
101             else
102             {
103                 const cim = (z.im >= 0) ? w : -w;
104                 return Complex_f((z.im / cast(float)(cim + cim)), cast(float)cim);
105             }
106         }
107     }
108 }
109 
110 struct Complex_d
111 {
112 nothrow:
113     double re, im;
114 
115     static Complex_d div(ref Complex_d x, ref Complex_d y)
116     {
117         if (fabs(y.re) < fabs(y.im))
118         {
119             const targ_ldouble r = y.re / y.im;
120             const targ_ldouble den = y.im + r * y.re;
121             return Complex_d(cast(double)((x.re * r + x.im) / den),
122                              cast(double)((x.im * r - x.re) / den));
123         }
124         else
125         {
126             const targ_ldouble r = y.im / y.re;
127             const targ_ldouble den = y.re + r * y.im;
128             return Complex_d(cast(double)((x.re + r * x.im) / den),
129                              cast(double)((x.im - r * x.re) / den));
130         }
131     }
132 
133     static Complex_d mul(ref Complex_d x, ref Complex_d y) pure
134     {
135         return Complex_d(x.re * y.re - x.im * y.im,
136                          x.im * y.re + x.re * y.im);
137     }
138 
139     static targ_ldouble abs(ref Complex_d z)
140     {
141         const targ_ldouble x = fabs(z.re);
142         const targ_ldouble y = fabs(z.im);
143         if (x == 0)
144             return y;
145         else if (y == 0)
146             return x;
147         else if (x > y)
148         {
149             const targ_ldouble temp = y / x;
150             return x * sqrt(1 + temp * temp);
151         }
152         else
153         {
154             const targ_ldouble temp = x / y;
155             return y * sqrt(1 + temp * temp);
156         }
157     }
158 
159     static Complex_d sqrtc(ref Complex_d z)
160     {
161         if (z.re == 0 && z.im == 0)
162         {
163             return Complex_d(0, 0);
164         }
165         else
166         {
167             const targ_ldouble x = fabs(z.re);
168             const targ_ldouble y = fabs(z.im);
169             targ_ldouble r, w;
170             if (x >= y)
171             {
172                 r = y / x;
173                 w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
174             }
175             else
176             {
177                 r = x / y;
178                 w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
179             }
180 
181             if (z.re >= 0)
182             {
183                 return Complex_d(cast(double)w, (z.im / cast(double)(w + w)));
184             }
185             else
186             {
187                 const cim = (z.im >= 0) ? w : -w;
188                 return Complex_d((z.im / cast(double)(cim + cim)), cast(double)cim);
189             }
190         }
191     }
192 }
193 
194 
195 struct Complex_ld
196 {
197 nothrow:
198     targ_ldouble re, im;
199 
200     static Complex_ld div(ref Complex_ld x, ref Complex_ld y)
201     {
202         if (fabsl(y.re) < fabsl(y.im))
203         {
204             const targ_ldouble r = y.re / y.im;
205             const targ_ldouble den = y.im + r * y.re;
206             return Complex_ld((x.re * r + x.im) / den,
207                               (x.im * r - x.re) / den);
208         }
209         else
210         {
211             const targ_ldouble r = y.im / y.re;
212             const targ_ldouble den = y.re + r * y.im;
213             return Complex_ld((x.re + r * x.im) / den,
214                               (x.im - r * x.re) / den);
215         }
216     }
217 
218     static Complex_ld mul(ref Complex_ld x, ref Complex_ld y) pure
219     {
220         return Complex_ld(x.re * y.re - x.im * y.im,
221                           x.im * y.re + x.re * y.im);
222     }
223 
224     static targ_ldouble abs(ref Complex_ld z)
225     {
226         const targ_ldouble x = fabsl(z.re);
227         const targ_ldouble y = fabsl(z.im);
228         if (x == 0)
229             return y;
230         else if (y == 0)
231             return x;
232         else if (x > y)
233         {
234             const targ_ldouble temp = y / x;
235             return x * sqrt(1 + temp * temp);
236         }
237         else
238         {
239             const targ_ldouble temp = x / y;
240             return y * sqrt(1 + temp * temp);
241         }
242     }
243 
244     static Complex_ld sqrtc(ref Complex_ld z)
245     {
246         if (z.re == 0 && z.im == 0)
247         {
248             return Complex_ld(targ_ldouble(0), targ_ldouble(0));
249         }
250         else
251         {
252             const targ_ldouble x = fabsl(z.re);
253             const targ_ldouble y = fabsl(z.im);
254             targ_ldouble r, w;
255             if (x >= y)
256             {
257                 r = y / x;
258                 w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
259             }
260             else
261             {
262                 r = x / y;
263                 w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
264             }
265 
266             if (z.re >= 0)
267             {
268                 return Complex_ld(w, z.im / (w + w));
269             }
270             else
271             {
272                 const cim = (z.im >= 0) ? w : -w;
273                 return Complex_ld(z.im / (cim + cim), cim);
274             }
275         }
276     }
277 }