A Survey of Gaussian Convolution Algorithms
complex_arith.h
Go to the documentation of this file.
1 
25 #ifndef _COMPLEX_ARITH_H_
26 #define _COMPLEX_ARITH_H_
27 
28 #include <math.h>
29 
31 typedef struct _complex_type
32 {
33  double real;
34  double imag;
36 
38 #define complex _complex_type
39 
40 #ifdef __GNUC__
41 __attribute__((pure,unused))
42 #endif
43 
44 static complex make_complex(double a, double b)
45 {
46  complex z;
47  z.real = a;
48  z.imag = b;
49  return z;
50 }
51 
52 #ifdef __GNUC__
53 __attribute__((pure,unused))
54 #endif
55 
57 {
58  complex result;
59  result.real = z.real;
60  result.imag = -z.imag;
61  return result;
62 }
63 
64 #ifdef __GNUC__
65 __attribute__((pure,unused))
66 #endif
67 
69 {
70  complex result;
71  result.real = w.real + z.real;
72  result.imag = w.imag + z.imag;
73  return result;
74 }
75 
76 #ifdef __GNUC__
77 __attribute__((pure,unused))
78 #endif
79 
81 {
82  complex result;
83  result.real = -z.real;
84  result.imag = -z.imag;
85  return result;
86 }
87 
88 #ifdef __GNUC__
89 __attribute__((pure,unused))
90 #endif
91 
93 {
94  complex result;
95  result.real = w.real - z.real;
96  result.imag = w.imag - z.imag;
97  return result;
98 }
99 
100 #ifdef __GNUC__
101 __attribute__((pure,unused))
102 #endif
103 
105 {
106  complex result;
107  result.real = w.real * z.real - w.imag * z.imag;
108  result.imag = w.real * z.imag + w.imag * z.real;
109  return result;
110 }
111 
112 #ifdef __GNUC__
113 __attribute__((pure,unused))
114 #endif
115 
117 {
118  complex result;
119 
120  /* There are two mathematically-equivalent formulas for the inverse. For
121  * accuracy, choose the formula with the smaller value of |ratio|.
122  */
123  if (fabs(z.real) >= fabs(z.imag))
124  {
125  double ratio = z.imag / z.real;
126  double denom = z.real + z.imag * ratio;
127  result.real = 1 / denom;
128  result.imag = -ratio / denom;
129  }
130  else
131  {
132  double ratio = z.real / z.imag;
133  double denom = z.real * ratio + z.imag;
134  result.real = ratio / denom;
135  result.imag = -1 / denom;
136  }
137 
138  return result;
139 }
140 
141 #ifdef __GNUC__
142 __attribute__((pure,unused))
143 #endif
144 
146 {
147  complex result;
148 
149  /* For accuracy, choose the formula with the smaller value of |ratio|. */
150  if (fabs(z.real) >= fabs(z.imag))
151  {
152  double ratio = z.imag / z.real;
153  double denom = z.real + z.imag * ratio;
154  result.real = (w.real + w.imag * ratio) / denom;
155  result.imag = (w.imag - w.real * ratio) / denom;
156  }
157  else
158  {
159  double ratio = z.real / z.imag;
160  double denom = z.real * ratio + z.imag;
161  result.real = (w.real * ratio + w.imag) / denom;
162  result.imag = (w.imag * ratio - w.real) / denom;
163  }
164 
165  return result;
166 }
167 
168 #ifdef __GNUC__
169 __attribute__((pure,unused))
170 #endif
171 
172 static double c_mag(complex z)
173 {
174  z.real = fabs(z.real);
175  z.imag = fabs(z.imag);
176 
177  /* For accuracy, choose the formula with the smaller value of |ratio|. */
178  if (z.real >= z.imag)
179  {
180  double ratio = z.imag / z.real;
181  return z.real * sqrt(1.0 + ratio * ratio);
182  }
183  else
184  {
185  double ratio = z.real / z.imag;
186  return z.imag * sqrt(1.0 + ratio * ratio);
187  }
188 }
189 
190 #ifdef __GNUC__
191 __attribute__((pure,unused))
192 #endif
193 
194 static double c_arg(complex z)
195 {
196  return atan2(z.imag, z.real);
197 }
198 
199 #ifdef __GNUC__
200 __attribute__((pure,unused))
201 #endif
202 
204 {
205  complex result;
206  double mag_w = c_mag(w);
207  double arg_w = c_arg(w);
208  double mag = pow(mag_w, z.real) * exp(-z.imag * arg_w);
209  double arg = z.real * arg_w + z.imag * log(mag_w);
210  result.real = mag * cos(arg);
211  result.imag = mag * sin(arg);
212  return result;
213 }
214 
215 #ifdef __GNUC__
216 __attribute__((pure,unused))
217 #endif
218 
219 static complex c_real_pow(complex w, double x)
220 {
221  complex result;
222  double mag = pow(c_mag(w), x);
223  double arg = c_arg(w) * x;
224  result.real = mag * cos(arg);
225  result.imag = mag * sin(arg);
226  return result;
227 }
228 
229 #ifdef __GNUC__
230 __attribute__((pure,unused))
231 #endif
232 
234 {
235  double r = c_mag(z);
236  complex result;
237  result.real = sqrt((r + z.real) / 2);
238  result.imag = sqrt((r - z.real) / 2);
239 
240  if (z.imag < 0)
241  result.imag = -result.imag;
242 
243  return result;
244 }
245 
246 #ifdef __GNUC__
247 __attribute__((pure,unused))
248 #endif
249 
251 {
252  double r = exp(z.real);
253  complex result;
254  result.real = r * cos(z.imag);
255  result.imag = r * sin(z.imag);
256  return result;
257 }
258 
259 #ifdef __GNUC__
260 __attribute__((pure,unused))
261 #endif
262 
264 {
265  complex result;
266  result.real = log(c_mag(z));
267  result.imag = c_arg(z);
268  return result;
269 }
270 
271 #endif /* _COMPLEX_ARITH_H_ */