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