1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "Prerequisites/BsPrerequisitesUtil.h"
6
7namespace bs
8{
9 /** @addtogroup Math
10 * @{
11 */
12
13 /** Complex numbers. */
14 template <class Type>
15 class Complex
16 {
17 public:
18 Complex() = default;
19
20 Complex(const Type& r, const Type& i)
21 : mReal(r), mImag(i) {}
22
23 Complex(const Complex& other)
24 : mReal(other.real()), mImag(other.imag()) {}
25
26 Complex<Type>& operator= (const Type& other)
27 {
28 mReal = other;
29 mImag = Type();
30
31 return *this;
32 }
33
34 Complex<Type>& operator+= (const Type& other)
35 {
36 mReal += other;
37
38 return *this;
39 }
40
41 Complex<Type>& operator-= (const Type& other)
42 {
43 mReal -= other;
44
45 return *this;
46 }
47
48 Complex<Type>& operator*= (const Type& other)
49 {
50 mReal *= other;
51 mImag *= other;
52
53 return *this;
54 }
55
56 Complex<Type>& operator/= (const Type& other)
57 {
58 mReal /= other;
59 mImag /= other;
60
61 return *this;
62 }
63
64 Complex<Type>& operator= (const Complex<Type>& other)
65 {
66 mReal = other.real();
67 mImag = other.imag();
68
69 return *this;
70 }
71
72 Complex<Type>& operator+= (const Complex<Type>& other)
73 {
74 mReal += other.real();
75 mImag += other.imag();
76
77 return *this;
78 }
79
80 Complex<Type>& operator-= (const Complex<Type>& other)
81 {
82 mReal -= other.real();
83 mImag -= other.imag();
84
85 return *this;
86 }
87
88 Complex<Type>& operator*= (const Complex<Type>& other)
89 {
90 const Type r = mReal * other.real() - mImag * other.imag();
91 mImag = mReal * other.imag() + mImag * other.real();
92 mReal = r;
93
94 return *this;
95 }
96
97 Complex<Type>& operator/= (const Complex<Type>& other)
98 {
99 const Type r = mReal * other.real() + mImag * other.imag();
100 const Type n = Complex::norm(other);
101 mImag = (mImag * other.real() - mReal * other.imag()) / n;
102 mReal = r / n;
103
104 return *this;
105 }
106
107 Complex<Type> operator+ (const Type& other) const
108 {
109 return Complex(mReal + other, mImag);
110 }
111
112 Complex<Type> operator- (const Type& other) const
113 {
114 return Complex(mReal - other, mImag);
115 }
116
117 Complex<Type> operator* (const Type& other) const
118 {
119 return Complex(mReal * other, mImag);
120 }
121
122 Complex<Type> operator/ (const Type& other) const
123 {
124 return Complex(mReal / other, mImag);
125 }
126
127 Complex<Type> operator+ (const Complex<Type>& other) const
128 {
129 return Complex(mReal + other.real(), mImag + other.imag());
130 }
131
132 Complex<Type> operator- (const Complex<Type>& other) const
133 {
134 return Complex(mReal - other.real(), mImag - other.imag());
135 }
136
137 Complex<Type> operator* (const Complex<Type>& other) const
138 {
139 Complex<Type> res = *this;
140
141 res *= other;
142
143 return res;
144 }
145
146 Complex<Type> operator/ (const Complex<Type>& other) const
147 {
148 Complex<Type> res = *this;
149
150 res /= other;
151
152 return res;
153 }
154
155 bool operator== (const Complex<Type>& other) const
156 {
157 return mReal == other.real() && mImag == other.imag();
158 }
159
160 bool operator== (const Type& other) const
161 {
162 return mReal == other && mImag == Type();
163 }
164
165 bool operator!= (const Complex<Type>& other) const
166 {
167 return mReal != other.real() || mImag != other.imag();
168 }
169
170 bool operator!= (const Type& other) const
171 {
172 return mReal != other || mImag != Type();
173 }
174
175 Type& real() { return mReal; }
176 Type& imag() { return mImag; }
177
178 const Type& real() const { return mReal; }
179 const Type& imag() const { return mImag; }
180
181 static Type abs(const Complex<Type>& other)
182 {
183 Type x = other.real();
184 Type y = other.imag();
185 const Type s = std::max(std::abs(x), std::abs(y));
186 if (s == Type())
187 return s;
188
189 x /= s;
190 y /= s;
191
192 return s * std::sqrt(x * x + y * y);
193 }
194
195 static Type arg(const Complex<Type>& other)
196 {
197 return std::atan2(other.imag(), other.real());
198 }
199
200 static Type norm(const Complex<Type>& other)
201 {
202 const Type x = other.real();
203 const Type y = other.imag();
204
205 return x * x + y * y;
206 }
207
208 static Complex<Type> conj(const Complex<Type>& other)
209 {
210 return Complex(other.real(), -other.imag());
211 }
212
213 static Complex<Type> polar(const Type& r, const Type& t = 0)
214 {
215 return Complex(r * std::cos(t), r * std::sin(t));
216 }
217
218 static Complex<Type> cos(const Complex<Type>& other)
219 {
220 const Type x = other.real();
221 const Type y = other.imag();
222
223 return Complex(std::cos(x) * std::cosh(y), -std::sin(x) * std::sinh(y));
224 }
225
226 static Complex<Type> cosh(const Complex<Type>& other)
227 {
228 const Type x = other.real();
229 const Type y = other.imag();
230
231 return Complex(std::cosh(x) * std::cos(y), std::sinh(x) * std::sin(y));
232 }
233
234 static Complex<Type> exp(const Complex<Type>& other)
235 {
236 return Complex::polar(std::exp(other.real()), other.imag());
237 }
238
239 static Complex<Type> log(const Complex<Type>& other)
240 {
241 return Complex(std::log(Complex::abs(other)), Complex::arg(other));
242 }
243
244 static Complex<Type> log10(const Complex<Type>& other)
245 {
246 return Complex::log(other) / std::log(Type(10));
247 }
248
249 static Complex<Type> pow(const Complex<Type>& other, const Type& i)
250 {
251 if (other.imag() == Type() && other.real() > Type())
252 return Complex(std::pow(other.real(), i), other.imag());
253
254 Complex<Type> t = Complex::log(other);
255 return Complex::polar(std::exp(i * t.real()), i * t.imag());
256 }
257
258 static Complex<Type> pow(const Complex<Type>& x, const Complex<Type>& y)
259 {
260 return Complex::exp(y * Complex::log(x));
261 }
262
263 static Complex<Type> pow(const Type& i, const Complex<Type>& other)
264 {
265 return i > Type() ?
266 Complex::polar(std::pow(i, other.real()), other.imag() * std::log(i))
267 : Complex::pow(Complex(i, Type()), other);
268 }
269
270 static Complex<Type> sin(const Complex<Type>& other)
271 {
272 const Type x = other.real();
273 const Type y = other.imag();
274
275 return Complex(std::sin(x) * std::cosh(y), std::cos(x) * std::sinh(y));
276 }
277
278 static Complex<Type> sinh(const Complex<Type>& other)
279 {
280 const Type x = other.real();
281 const Type y = other.imag();
282
283 return Complex(std::sinh(x) * std::cos(y), std::cosh(x) * std::sin(y));
284 }
285
286 static Complex<Type> sqrt(const Complex<Type>& other)
287 {
288 const Type x = other.real();
289 const Type y = other.imag();
290
291 if (x == Type())
292 {
293 Type t = std::sqrt(std::abs(y) / 2);
294 return Complex(t, y < Type() ? -t : t);
295 }
296 else
297 {
298 Type t = std::sqrt(2 * (Complex::abs(other) + std::abs(x)));
299 Type u = t / 2;
300 return x > Type() ? Complex(u, y / t)
301 : Complex(std::abs(y) / t, y < Type() ? -u : u);
302 }
303 }
304
305 static Complex<Type> tan(const Complex<Type>& other)
306 {
307 return Complex::sin(other) / Complex::cos(other);
308 }
309
310 static Complex<Type> tanh(const Complex<Type>& other)
311 {
312 return Complex::sinh(other) / Complex::cosh(other);
313 }
314
315 friend std::ostream& operator<< (std::ostream& os, const Complex<Type> other)
316 {
317 return os << other.real() << ", " << other.imag();
318 }
319
320 private:
321 Type mReal;
322 Type mImag;
323 };
324
325 /** @} */
326}
327