1 package org.djutils.complex;
2
3
4
5
6
7
8
9
10
11
12
13
14 public class Complex
15 {
16
17 @SuppressWarnings("checkstyle:visibilitymodifier")
18 public final double re;
19
20
21 @SuppressWarnings("checkstyle:visibilitymodifier")
22 public final double im;
23
24
25 public static final Complex ZERO = new Complex(0, 0);
26
27
28 public static final Complex ONE = new Complex(1, 0);
29
30
31 public static final Complex MINUS_ONE = new Complex(-1, 0);
32
33
34 public static final Complex I = new Complex(0, 1);
35
36
37 public static final Complex MINUS_I = new Complex(0, -1);
38
39
40
41
42
43
44 public Complex(final double re, final double im)
45 {
46 this.re = re;
47 this.im = im;
48 }
49
50
51
52
53
54 public Complex(final double re)
55 {
56 this.re = re;
57 this.im = 0;
58 }
59
60
61
62
63
64 public double getRe()
65 {
66 return this.re;
67 }
68
69
70
71
72
73 public double getIm()
74 {
75 return this.im;
76 }
77
78
79
80
81
82
83
84
85 public double norm()
86 {
87 return hypot(this.re, this.im);
88 }
89
90
91 private static final double EPSILONSQRT = Math.sqrt(Math.ulp(1.0) / 2);
92
93 private static final double SQRT_OF_MIN_VALUE = Math.sqrt(Double.MIN_VALUE);
94
95 private static final double SQRT_OF_MAX_VALUE = Math.sqrt(Double.MAX_VALUE);
96
97
98
99
100
101
102
103
104 public static double hypot(final double x, final double y)
105 {
106 if (x != x || y != y)
107 {
108 return Double.NaN;
109 }
110 double absX = Math.abs(x);
111 double absY = Math.abs(y);
112 if (absX == Double.POSITIVE_INFINITY || absY == Double.POSITIVE_INFINITY)
113 {
114 return Double.POSITIVE_INFINITY;
115 }
116 if (absX < absY)
117 {
118 double swap = absX;
119 absX = absY;
120 absY = swap;
121 }
122 if (absY <= absX * EPSILONSQRT)
123 {
124 return absX;
125 }
126 double scale = SQRT_OF_MIN_VALUE;
127 if (absX > SQRT_OF_MAX_VALUE)
128 {
129 absX *= scale;
130 absY *= scale;
131 scale = 1.0 / scale;
132 }
133 else if (absY < SQRT_OF_MIN_VALUE)
134 {
135 absX /= scale;
136 absY /= scale;
137 }
138 else
139 {
140 scale = 1.0;
141 }
142 double h = Math.sqrt(Math.fma(absX, absX, absY * absY));
143 double hsq = h * h;
144 double xsq = absX * absX;
145 double a = Math.fma(-absY, absY, hsq - xsq) + Math.fma(h, h, -hsq) - Math.fma(absX, absX, -xsq);
146 return scale * (h - a / (2.0 * h));
147 }
148
149
150
151
152
153
154
155 public double phi()
156 {
157 return Math.atan2(this.im, this.re);
158 }
159
160
161
162
163
164
165 public boolean isReal()
166 {
167 return this.im == 0.0;
168 }
169
170
171
172
173
174
175 public boolean isImaginary()
176 {
177 return this.re == 0.0;
178 }
179
180
181
182
183
184 public Complex conjugate()
185 {
186 return new Complex(this.re, -this.im);
187 }
188
189
190
191
192
193
194 public Complex rotate(final double angle)
195 {
196 double sin = Math.sin(angle);
197 double cos = Math.cos(angle);
198 return new Complex(this.re * cos - this.im * sin, this.im * cos + this.re * sin);
199 }
200
201
202
203
204
205
206 public Complex plus(final Complex rightOperand)
207 {
208 return new Complex(this.re + rightOperand.re, this.im + rightOperand.im);
209 }
210
211
212
213
214
215
216 public Complex plus(final double rightOperand)
217 {
218 return new Complex(this.re + rightOperand, this.im);
219 }
220
221
222
223
224
225
226 public Complex minus(final Complex rightOperand)
227 {
228 return new Complex(this.re - rightOperand.re, this.im - rightOperand.im);
229 }
230
231
232
233
234
235
236 public Complex minus(final double rightOperand)
237 {
238 return new Complex(this.re - rightOperand, this.im);
239 }
240
241
242
243
244
245
246 public Complex times(final Complex rightOperand)
247 {
248 return new Complex(this.re * rightOperand.re - this.im * rightOperand.im,
249 this.im * rightOperand.re + this.re * rightOperand.im);
250 }
251
252
253
254
255
256
257 public Complex times(final double rightOperand)
258 {
259 return new Complex(this.re * rightOperand, this.im * rightOperand);
260 }
261
262
263
264
265
266
267 public Complex reciprocal()
268 {
269 double divisor = this.re * this.re + this.im * this.im;
270 if (0.0 == divisor)
271 {
272 return new Complex(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
273 }
274 return new Complex(this.re / divisor, -this.im / divisor);
275 }
276
277
278
279
280
281
282
283 public Complex divideBy(final Complex rightOperand)
284 {
285 if (rightOperand.re == 0 && rightOperand.im == 0)
286 {
287 return new Complex(this.re / 0.0, this.im / 0.0);
288 }
289 return this.times(rightOperand.reciprocal());
290 }
291
292
293
294
295
296
297
298 public Complex divideBy(final double rightOperand)
299 {
300 return new Complex(this.re / rightOperand, this.im / rightOperand);
301 }
302
303 @Override
304 public String toString()
305 {
306 return "Complex [re=" + this.re + ", im=" + this.im + "]";
307 }
308
309 @Override
310 public int hashCode()
311 {
312 final int prime = 31;
313 int result = 1;
314 long temp;
315 temp = Double.doubleToLongBits(this.im);
316 result = prime * result + (int) (temp ^ (temp >>> 32));
317 temp = Double.doubleToLongBits(this.re);
318 result = prime * result + (int) (temp ^ (temp >>> 32));
319 return result;
320 }
321
322 @SuppressWarnings("checkstyle:needbraces")
323 @Override
324 public boolean equals(final Object obj)
325 {
326 if (this == obj)
327 return true;
328 if (obj == null)
329 return false;
330 if (getClass() != obj.getClass())
331 return false;
332 Complex other = (Complex) obj;
333 if (Double.doubleToLongBits(this.im) != Double.doubleToLongBits(other.im))
334 return false;
335 if (Double.doubleToLongBits(this.re) != Double.doubleToLongBits(other.re))
336 return false;
337 return true;
338 }
339
340 }