Expression Templates Library (ETL)
complex.hpp
Go to the documentation of this file.
1 //=======================================================================
2 // Copyright (c) 2014-2023 Baptiste Wicht
3 // Distributed under the terms of the MIT License.
4 // (See accompanying file LICENSE or copy at
5 // http://opensource.org/licenses/MIT)
6 //=======================================================================
7 
19 #pragma once
20 
21 namespace etl {
22 
30 template <typename T>
31 struct complex {
32  using value_type = T;
33 
36 
42  constexpr complex(const T& re = T(), const T& im = T()) : real(re), imag(im) {
43  // Nothing else to init
44  }
45 
50  constexpr complex(const complex& rhs) = default;
51 
58  template <typename X>
59  constexpr complex(const complex<X>& rhs) : real(rhs.real), imag(rhs.imag) {
60  // Nothing else to init
61  }
62 
68  complex& operator=(const T& rhs) noexcept {
69  real = rhs;
70  imag = 0.0;
71 
72  return *this;
73  }
74 
80  complex& operator=(const complex& rhs) noexcept = default;
81 
87  complex& operator=(const std::complex<T>& rhs) noexcept {
88  real = rhs.real();
89  imag = rhs.imag();
90 
91  return *this;
92  }
93 
99  template <typename X>
101  real += rhs.real;
102  imag += rhs.imag;
103 
104  return *this;
105  }
106 
112  template <typename X>
114  real -= rhs.real;
115  imag -= rhs.imag;
116 
117  return *this;
118  }
119 
125  template <typename X>
127  T ac = real * rhs.real;
128  T bd = imag * rhs.imag;
129 
130  T bc = imag * rhs.real;
131  T ad = real * rhs.imag;
132 
133  real = ac - bd;
134  imag = bc + ad;
135 
136  return *this;
137  }
138 
144  template <typename X>
146  T ac = real * rhs.real;
147  T bd = imag * rhs.imag;
148 
149  T bc = imag * rhs.real;
150  T ad = real * rhs.imag;
151 
152  T frac = rhs.real * rhs.real + rhs.imag * rhs.imag;
153 
154  real = (ac + bd) / frac;
155  imag = (bc - ad) / frac;
156 
157  return *this;
158  }
159 };
160 
167 template <typename T>
168 inline bool operator==(const complex<T>& lhs, const complex<T>& rhs) {
169  return lhs.real == rhs.real && lhs.imag == rhs.imag;
170 }
171 
178 template <typename T>
179 inline bool operator!=(const complex<T>& lhs, const complex<T>& rhs) {
180  return !(lhs == rhs);
181 }
182 
188 template <typename T>
190  return {-rhs.real, -rhs.imag};
191 }
192 
199 template <typename T>
200 inline complex<T> operator+(const complex<T>& lhs, const complex<T>& rhs) {
201  return {lhs.real + rhs.real, lhs.imag + rhs.imag};
202 }
203 
210 template <typename T>
211 inline complex<T> operator-(const complex<T>& lhs, const complex<T>& rhs) {
212  return {lhs.real - rhs.real, lhs.imag - rhs.imag};
213 }
214 
221 template <typename T>
222 inline complex<T> operator*(const complex<T>& lhs, const complex<T>& rhs) {
223  T ac = lhs.real * rhs.real;
224  T bd = lhs.imag * rhs.imag;
225 
226  T bc = lhs.imag * rhs.real;
227  T ad = lhs.real * rhs.imag;
228 
229  return {ac - bd, bc + ad};
230 }
231 
238 template <typename T>
239 inline complex<T> operator*(const complex<T>& lhs, T rhs) {
240  return {lhs.real * rhs, lhs.imag * rhs};
241 }
242 
249 template <typename T>
250 inline complex<T> operator*(T lhs, const complex<T>& rhs) {
251  return {lhs * rhs.real, lhs * rhs.imag};
252 }
253 
260 template <typename T>
261 inline complex<T> operator/(const complex<T>& lhs, T rhs) {
262  return {lhs.real / rhs, lhs.imag / rhs};
263 }
264 
271 template <typename T>
272 inline complex<T> operator/(const complex<T>& lhs, const complex<T>& rhs) {
273  T ac = lhs.real * rhs.real;
274  T bd = lhs.imag * rhs.imag;
275 
276  T bc = lhs.imag * rhs.real;
277  T ad = lhs.real * rhs.imag;
278 
279  T frac = rhs.real * rhs.real + rhs.imag * rhs.imag;
280 
281  return {(ac + bd) / frac, (bc - ad) / frac};
282 }
283 
289 template <typename T>
291  auto x = z.real;
292  auto y = z.imag;
293  auto s = std::max(std::abs(x), std::abs(y));
294 
295  if (s == T()) {
296  return s;
297  }
298 
299  x = x / s;
300  y = y / s;
301 
302  return s * std::sqrt(x * x + y * y);
303 }
304 
310 template <typename T>
312  auto x = z.real;
313  auto y = z.imag;
314 
315  return atan2(y, x);
316 }
317 
323 template <typename T>
325  auto x = z.real;
326  auto y = z.imag;
327 
328  if (x == T()) {
329  auto t = std::sqrt(std::abs(y) / 2);
330  return {t, y < T() ? -t : t};
331  } else {
332  auto t = std::sqrt(2 * (abs(z) + std::abs(x)));
333  auto u = t / 2;
334 
335  if (x > T()) {
336  return {u, y / t};
337  } else {
338  return {std::abs(y) / t, y < T() ? -u : u};
339  }
340  }
341 }
342 
348 template <typename T>
350  return complex<T>(T(1)) / sqrt(z);
351 }
352 
358 template <typename T>
360  auto z_abs = etl::abs(z);
361  auto z_arg = etl::arg(z);
362 
363  auto new_abs = std::cbrt(z_abs);
364  auto new_arg = z_arg / 3.0f;
365 
366  return {new_abs * std::cos(new_arg), new_abs * std::sin(new_arg)};
367 }
368 
374 template <typename T>
376  return complex<T>(T(1)) / cbrt(z);
377 }
378 
384 template <typename T>
386  return {std::log(etl::abs(z)), etl::arg(z)};
387 }
388 
394 template <typename T>
396  return etl::log(z) / etl::log(etl::complex<T>{T(2)});
397 }
398 
404 template <typename T>
406  return etl::log(z) / etl::log(etl::complex<T>{T(10)});
407 }
408 
414 template <typename T>
416  return {std::sin(z.real) * std::cosh(z.imag), std::cos(z.real) * std::sinh(z.imag)};
417 }
418 
424 template <typename T>
426  return {std::cos(z.real) * std::cosh(z.imag), -std::sin(z.real) * std::sinh(z.imag)};
427 }
428 
434 template <typename T>
436  return sin(z) / cos(z);
437 }
438 
444 template <typename T>
446  return {std::cosh(z.real) * std::cos(z.imag), std::sinh(z.real) * std::sin(z.imag)};
447 }
448 
454 template <typename T>
456  return {std::sinh(z.real) * std::cos(z.imag), std::cosh(z.real) * std::sin(z.imag)};
457 }
458 
464 template <typename T>
466  return sinh(z) / cosh(z);
467 }
468 
474 template <typename T>
476  return {x.imag, x.real};
477 }
478 
484 template <typename T>
486  return {-x.imag, x.real};
487 }
488 
494 template <typename T>
496  return {x.imag, -x.real};
497 }
498 
504 template <typename T>
505 inline complex<T> conj(const complex<T>& c) {
506  return {c.real, -c.imag};
507 }
508 
514 template <typename T>
515 inline T get_imag(const std::complex<T>& c) {
516  return c.imag();
517 }
518 
524 template <typename T>
525 inline T get_imag(const etl::complex<T>& c) {
526  return c.imag;
527 }
528 
534 template <typename T>
535 inline T get_real(const std::complex<T>& c) {
536  return c.real();
537 }
538 
544 template <typename T>
545 inline T get_real(const etl::complex<T>& c) {
546  return c.real;
547 }
548 
554 template <typename T>
555 inline std::complex<T> get_conj(const std::complex<T>& c) {
556  return std::conj(c);
557 }
558 
564 template <typename T>
566  return {c.real, -c.imag};
567 }
568 
575 template <typename T>
576 std::ostream& operator<<(std::ostream& os, const etl::complex<T>& c) {
577  return os << "C(" << c.real << "," << c.imag << ")";
578 }
579 
580 } //end of namespace etl
complex< T > inverse(complex< T > x)
Returns the inverse of the complex number.
Definition: complex.hpp:475
auto s(T &&value)
Force the evaluation of the given expression.
Definition: stop.hpp:18
auto sin(E &&value) -> detail::unary_helper< E, sin_unary_op >
Apply sinus on each value of the given expression.
Definition: function_expression_builder.hpp:114
auto sinh(E &&value) -> detail::unary_helper< E, sinh_unary_op >
Apply hyperbolic sinus on each value of the given expression.
Definition: function_expression_builder.hpp:144
auto max(L &&lhs, R &&rhs)
Create an expression with the max value of lhs or rhs.
Definition: expression_builder.hpp:65
Complex number implementation.
Definition: complex.hpp:31
auto real()
Extract the real part of a complex expression.
Definition: expression_able.hpp:79
auto log2(E &&value) -> detail::unary_helper< E, log2_unary_op >
Apply logarithm (base 2) on each value of the given expression.
Definition: function_expression_builder.hpp:74
auto sqrt(E &&value) -> detail::unary_helper< E, sqrt_unary_op >
Apply square root on each value of the given expression.
Definition: function_expression_builder.hpp:24
T value_type
The value type.
Definition: complex.hpp:32
bool operator!=(const complex< T > &lhs, const complex< T > &rhs)
Test two complex numbers for inequality.
Definition: complex.hpp:179
auto cosh(E &&value) -> detail::unary_helper< E, cosh_unary_op >
Apply hyperbolic cosinus on each value of the given expression.
Definition: function_expression_builder.hpp:134
auto cbrt(E &&value) -> detail::unary_helper< E, cbrt_unary_op >
Apply cubic root on each value of the given expression.
Definition: function_expression_builder.hpp:44
complex< T > inverse_conj(complex< T > x)
Returns the inverse of the conjugate of the complex number.
Definition: complex.hpp:485
auto operator*(LE &&lhs, RE rhs)
Builds an expression representing the multiplication of lhs and rhs (scalar)
Definition: binary_expression_builder.hpp:149
complex< T > sin(complex< T > z)
Computes the sinus of the complex input.
Definition: complex.hpp:415
auto conj(E &&value)
Apply the conjugate operation on each complex value of the given expression.
Definition: expression_builder.hpp:206
auto abs(E &&value)
Apply absolute on each value of the given expression.
Definition: expression_builder.hpp:54
complex< T > cbrt(complex< T > z)
Computes the complex cubic root of the input.
Definition: complex.hpp:359
complex & operator/=(const complex< X > &rhs)
Divides a complex number.
Definition: complex.hpp:145
auto cos(E &&value) -> detail::unary_helper< E, cos_unary_op >
Apply cosinus on each value of the given expression.
Definition: function_expression_builder.hpp:104
Root namespace for the ETL library.
Definition: adapter.hpp:15
complex & operator+=(const complex< X > &rhs)
Adds a complex number.
Definition: complex.hpp:100
auto tanh(E &&value) -> detail::unary_helper< E, tanh_unary_op >
Apply hyperbolic tangent on each value of the given expression.
Definition: function_expression_builder.hpp:124
complex< T > cosh(complex< T > z)
Computes the hyperbolic cosine of the complex input.
Definition: complex.hpp:445
auto operator+(LE &&lhs, RE &&rhs)
Builds an expression representing the addition of lhs and rhs.
Definition: binary_expression_builder.hpp:38
T get_imag(const std::complex< T > &c)
Returns the imaginary part of the given complex number.
Definition: complex.hpp:515
complex & operator=(const std::complex< T > &rhs) noexcept
Assign a complex number by copy.
Definition: complex.hpp:87
auto invcbrt(E &&value) -> detail::unary_helper< E, invcbrt_unary_op >
Apply inverse cubic root on each value of the given expression.
Definition: function_expression_builder.hpp:54
auto log10(E &&value) -> detail::unary_helper< E, log10_unary_op >
Apply logarithm (base 10) on each value of the given expression.
Definition: function_expression_builder.hpp:84
T abs(complex< T > z)
Computes the magnitude of the given complex number.
Definition: complex.hpp:290
constexpr complex(const complex< X > &rhs)
Construct a complex number by copy from another complex with different inner type.
Definition: complex.hpp:59
auto tan(E &&value) -> detail::unary_helper< E, tan_unary_op >
Apply tangent on each value of the given expression.
Definition: function_expression_builder.hpp:94
complex< T > sqrt(complex< T > z)
Computes the complex square root of the input.
Definition: complex.hpp:324
std::complex< T > get_conj(const std::complex< T > &c)
Returns the conjugate of the given complex number.
Definition: complex.hpp:555
complex & operator*=(const complex< X > &rhs)
Multipliies a complex number.
Definition: complex.hpp:126
T get_real(const std::complex< T > &c)
Returns the real part of the given complex number.
Definition: complex.hpp:535
complex & operator=(const T &rhs) noexcept
Assign a real part to the complex number.
Definition: complex.hpp:68
complex< T > cos(complex< T > z)
Computes the cosine of the complex input.
Definition: complex.hpp:425
complex< T > log(complex< T > z)
Computes the complex logarithm, in base e, of the input.
Definition: complex.hpp:385
complex< T > conj_inverse(complex< T > x)
Returns the conjugate of the inverse of the complex number.
Definition: complex.hpp:495
constexpr complex(const T &re=T(), const T &im=T())
Construct a complex number.
Definition: complex.hpp:42
value_type real
The real part.
Definition: complex.hpp:34
complex< T > conj(const complex< T > &c)
Returns the conjugate of the complex number.
Definition: complex.hpp:505
bool operator==(const complex< T > &lhs, const complex< T > &rhs)
Test two complex numbers for equality.
Definition: complex.hpp:168
value_type imag
The imaginary part.
Definition: complex.hpp:35
auto operator/(LE &&lhs, RE &&rhs)
Builds an expression representing the division of lhs and rhs.
Definition: binary_expression_builder.hpp:77
auto log(E &&value) -> detail::unary_helper< E, log_unary_op >
Apply logarithm (base e) on each value of the given expression.
Definition: function_expression_builder.hpp:64
complex & operator-=(const complex< X > &rhs)
Subtracts a complex number.
Definition: complex.hpp:113
auto invsqrt(E &&value) -> detail::unary_helper< E, invsqrt_unary_op >
Apply inverse square root on each value of the given expression.
Definition: function_expression_builder.hpp:34
complex< T > sinh(complex< T > z)
Computes the hyperbolic sinus of the complex input.
Definition: complex.hpp:455
auto operator-(LE &&lhs, RE &&rhs)
Builds an expression representing the subtraction of lhs and rhs.
Definition: binary_expression_builder.hpp:25
auto imag()
Extract the imag part of a complex expression.
Definition: expression_able.hpp:87
T arg(complex< T > z)
Computes the phase angle of the given complex number.
Definition: complex.hpp:311