tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
complex.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2021 Tobias Hienzsch
3
4#ifndef TETL_COMPLEX_COMPLEX_HPP
5#define TETL_COMPLEX_COMPLEX_HPP
6
7#include <etl/_cmath/atan2.hpp>
8#include <etl/_cmath/cos.hpp>
9#include <etl/_cmath/cosh.hpp>
10#include <etl/_cmath/hypot.hpp>
11#include <etl/_cmath/log.hpp>
12#include <etl/_cmath/sin.hpp>
13#include <etl/_cmath/sinh.hpp>
14#include <etl/_concepts/floating_point.hpp>
15#include <etl/_concepts/integral.hpp>
16#include <etl/_cstddef/size_t.hpp>
17#include <etl/_tuple/is_tuple_like.hpp>
18#include <etl/_tuple/tuple_element.hpp>
19#include <etl/_tuple/tuple_size.hpp>
20#include <etl/_type_traits/integral_constant.hpp>
21#include <etl/_utility/move.hpp>
22
23namespace etl {
24
25/// \ingroup complex
26/// @{
27
28/// \brief A complex number
29/// \headerfile etl/complex.hpp
30
31template <typename T>
32struct complex {
33 using value_type = T;
34
35 constexpr complex(T const& re = T(), T const& im = T());
36 constexpr complex(complex const& other) = default;
37 template <typename X>
38 explicit(sizeof(X) > sizeof(T)) constexpr complex(complex<X> const& other);
39
40 constexpr auto operator=(T const& val) -> complex<T>&;
41 constexpr auto operator=(complex const& other) -> complex& = default;
42 template <typename X>
43 constexpr auto operator=(complex<X> const& other) -> complex<T>&;
44
45 [[nodiscard]] constexpr auto real() const -> T;
46 constexpr auto real(T val) -> void;
47
48 [[nodiscard]] constexpr auto imag() const -> T;
49 constexpr auto imag(T val) -> void;
50
51 constexpr auto operator+=(T const& val) -> complex<T>&;
52 constexpr auto operator-=(T const& val) -> complex<T>&;
53 constexpr auto operator*=(T const& val) -> complex<T>&;
54 constexpr auto operator/=(T const& val) -> complex<T>&;
55
56 template <typename X>
57 constexpr auto operator+=(complex<X> const& val) -> complex<T>&;
58 template <typename X>
59 constexpr auto operator-=(complex<X> const& val) -> complex<T>&;
60 template <typename X>
61 constexpr auto operator*=(complex<X> const& val) -> complex<T>&;
62 template <typename X>
63 constexpr auto operator/=(complex<X> const& val) -> complex<T>&;
64
65 template <size_t I, typename X>
66 friend constexpr auto get(complex<X>&) noexcept -> X&;
67
68 template <size_t I, typename X>
69 friend constexpr auto get(complex<X>&&) noexcept -> X&&;
70
71 template <size_t I, typename X>
72 friend constexpr auto get(complex<X> const&) noexcept -> X const&;
73
74 template <size_t I, typename X>
75 friend constexpr auto get(complex<X> const&&) noexcept -> X const&&;
76
77 friend constexpr auto operator==(complex const& lhs, complex const& rhs) -> bool
78 {
79 return lhs.real() == rhs.real() and lhs.imag() == rhs.imag();
80 }
81
82 friend constexpr auto operator==(complex const& lhs, T const& rhs) -> bool
83 {
84 return lhs.real() == rhs and lhs.imag() == T{};
85 }
86
87private:
88 value_type _real;
89 value_type _imag;
90};
91
92template <typename T>
93inline constexpr auto is_tuple_like<etl::complex<T>> = true;
94
95template <typename T>
96struct tuple_size<etl::complex<T>> : etl::integral_constant<etl::size_t, 2> { };
97
98template <size_t I, typename T>
99struct tuple_element<I, etl::complex<T>> {
100 static_assert(I < 2, "Index out of range for etl::complex");
101 using type = T;
102};
103
104template <size_t I, typename X>
105constexpr auto get(complex<X>& z) noexcept -> X&
106{
107 static_assert(I < 2, "Index out of range for etl::complex");
108 if constexpr (I == 0) {
109 return z._real;
110 } else {
111 return z._imag;
112 }
113}
114
115template <size_t I, typename X>
116constexpr auto get(complex<X>&& z) noexcept -> X&&
117{
118 static_assert(I < 2, "Index out of range for etl::complex");
119 if constexpr (I == 0) {
120 return etl::move(z._real);
121 } else {
122 return etl::move(z._imag);
123 }
124}
125
126template <size_t I, typename X>
127constexpr auto get(complex<X> const& z) noexcept -> X const&
128{
129 static_assert(I < 2, "Index out of range for etl::complex");
130 if constexpr (I == 0) {
131 return z._real;
132 } else {
133 return z._imag;
134 }
135}
136
137template <size_t I, typename X>
138constexpr auto get(complex<X> const&& z) noexcept -> X const&&
139{
140 static_assert(I < 2, "Index out of range for etl::complex");
141 if constexpr (I == 0) {
142 return etl::move(z._real);
143 } else {
144 return etl::move(z._imag);
145 }
146}
147
148template <typename T>
149constexpr complex<T>::complex(T const& re, T const& im)
150 : _real{re}
151 , _imag{im}
152{
153}
154
155template <typename T>
156template <typename X>
157constexpr complex<T>::complex(complex<X> const& other)
158 : _real{static_cast<T>(other.real())}
159 , _imag{static_cast<T>(other.imag())}
160{
161}
162
163template <typename T>
164constexpr auto complex<T>::real() const -> T
165{
166 return _real;
167}
168
169template <typename T>
170constexpr auto complex<T>::real(T const val) -> void
171{
172 _real = val;
173}
174
175template <typename T>
176constexpr auto complex<T>::imag() const -> T
177{
178 return _imag;
179}
180
181template <typename T>
182constexpr auto complex<T>::imag(T const val) -> void
183{
184 _imag = val;
185}
186
187template <typename T>
188constexpr auto complex<T>::operator=(T const& val) -> complex<T>&
189{
190 _real = val;
191 _imag = T{};
192 return *this;
193}
194
195template <typename T>
196constexpr auto complex<T>::operator+=(T const& val) -> complex<T>&
197{
198 _real += val;
199 return *this;
200}
201
202template <typename T>
203constexpr auto complex<T>::operator-=(T const& val) -> complex<T>&
204{
205 _real -= val;
206 return *this;
207}
208
209template <typename T>
210constexpr auto complex<T>::operator*=(T const& val) -> complex<T>&
211{
212 (*this) *= complex<T>{val};
213 return *this;
214}
215
216template <typename T>
217constexpr auto complex<T>::operator/=(T const& val) -> complex<T>&
218{
219 (*this) /= complex<T>{val};
220 return *this;
221}
222
223template <typename T>
224template <typename X>
225constexpr auto complex<T>::operator+=(complex<X> const& val) -> complex<T>&
226{
227 _real += val.real();
228 _imag += val.imag();
229 return *this;
230}
231
232template <typename T>
233template <typename X>
234constexpr auto complex<T>::operator-=(complex<X> const& val) -> complex<T>&
235{
236 _real -= val.real();
237 _imag -= val.imag();
238 return *this;
239}
240
241template <typename T>
242template <typename X>
243constexpr auto complex<T>::operator*=(complex<X> const& val) -> complex<T>&
244{
245 auto const r = static_cast<T>((_real * val.real()) - (_imag * val.imag()));
246 _imag = static_cast<T>(_real * val.imag() + _imag * val.real());
247 _real = r;
248 return *this;
249}
250
251template <typename T>
252template <typename X>
253constexpr auto complex<T>::operator/=(complex<X> const& val) -> complex<T>&
254{
255 auto const norm = [](auto const& c) {
256 auto const x = c.real();
257 auto const y = c.imag();
258 return static_cast<T>(x * x + y * y);
259 };
260
261 auto const r = static_cast<T>(_real * val.real() + _imag * val.imag());
262 auto const n = norm(val);
263 _imag = (_imag * val.real() - _real * val.imag()) / n;
264 _real = r / n;
265 return *this;
266}
267
268template <typename T>
269constexpr auto operator+(complex<T> const& val) -> complex<T>
270{
271 return val;
272}
273
274template <typename T>
275constexpr auto operator-(complex<T> const& val) -> complex<T>
276{
277 return {static_cast<T>(-val.real()), static_cast<T>(-val.imag())};
278}
279
280template <typename T>
281[[nodiscard]] constexpr auto operator+(complex<T> const& lhs, complex<T> const& rhs) -> complex<T>
282{
283 return complex<T>(lhs) += rhs;
284}
285
286template <typename T>
287[[nodiscard]] constexpr auto operator+(complex<T> const& lhs, T const& rhs) -> complex<T>
288{
289 return complex<T>(lhs) += rhs;
290}
291
292template <typename T>
293[[nodiscard]] constexpr auto operator+(T const& lhs, complex<T> const& rhs) -> complex<T>
294{
295 return complex<T>(lhs) += rhs;
296}
297
298template <typename T>
299[[nodiscard]] constexpr auto operator-(complex<T> const& lhs, complex<T> const& rhs) -> complex<T>
300{
301 return complex<T>(lhs) -= rhs;
302}
303
304template <typename T>
305[[nodiscard]] constexpr auto operator-(complex<T> const& lhs, T const& rhs) -> complex<T>
306{
307 return complex<T>(lhs) -= rhs;
308}
309
310template <typename T>
311[[nodiscard]] constexpr auto operator-(T const& lhs, complex<T> const& rhs) -> complex<T>
312{
313 return complex<T>(lhs) -= rhs;
314}
315
316template <typename T>
317[[nodiscard]] constexpr auto operator*(complex<T> const& lhs, complex<T> const& rhs) -> complex<T>
318{
319 return complex<T>(lhs) *= rhs;
320}
321
322template <typename T>
323[[nodiscard]] constexpr auto operator*(complex<T> const& lhs, T const& rhs) -> complex<T>
324{
325 return complex<T>(lhs) *= rhs;
326}
327
328template <typename T>
329[[nodiscard]] constexpr auto operator*(T const& lhs, complex<T> const& rhs) -> complex<T>
330{
331 return complex<T>(lhs) *= rhs;
332}
333
334template <typename T>
335[[nodiscard]] constexpr auto operator/(complex<T> const& lhs, complex<T> const& rhs) -> complex<T>
336{
337 return complex<T>(lhs) /= rhs;
338}
339
340template <typename T>
341[[nodiscard]] constexpr auto operator/(complex<T> const& lhs, T const& rhs) -> complex<T>
342{
343 return complex<T>(lhs) /= rhs;
344}
345
346template <typename T>
347[[nodiscard]] constexpr auto operator/(T const& lhs, complex<T> const& rhs) -> complex<T>
348{
349 return complex<T>(lhs) /= rhs;
350}
351
352// NOLINTNEXTLINE(modernize-concat-nested-namespaces)
353inline namespace literals {
354inline namespace complex_literals {
355
356constexpr auto operator""_il(long double d) -> complex<long double>
357{
358 return {0.0L, static_cast<long double>(d)};
359}
360
361constexpr auto operator""_il(unsigned long long d) -> complex<long double>
362{
363 return {0.0L, static_cast<long double>(d)};
364}
365
366constexpr auto operator""_i(long double d) -> complex<double>
367{
368 return {0.0, static_cast<double>(d)};
369}
370
371constexpr auto operator""_i(unsigned long long d) -> complex<double>
372{
373 return {0.0, static_cast<double>(d)};
374}
375
376constexpr auto operator""_if(long double d) -> complex<float>
377{
378 return {0.0F, static_cast<float>(d)};
379}
380
381constexpr auto operator""_if(unsigned long long d) -> complex<float>
382{
383 return {0.0F, static_cast<float>(d)};
384}
385
386} // namespace complex_literals
387} // namespace literals
388
389template <typename T>
390[[nodiscard]] constexpr auto abs(complex<T> const& z) -> T
391{
392 return hypot(z.real(), z.imag());
393}
394
395template <typename T>
396[[nodiscard]] constexpr auto arg(complex<T> const& z) noexcept -> T
397{
398 return etl::atan2(z.imag(), z.real());
399}
400
401template <floating_point Float>
402[[nodiscard]] constexpr auto arg(Float f) noexcept -> complex<Float>
403{
404 return etl::arg(etl::complex<Float>(f));
405}
406
407template <integral Integer>
408[[nodiscard]] constexpr auto arg(Integer i) noexcept -> complex<double>
409{
410 return etl::arg(etl::complex<double>(i));
411}
412
413template <typename T>
414[[nodiscard]] constexpr auto conj(complex<T> const& z) noexcept -> complex<T>
415{
416 return complex<T>(z.real(), -z.imag());
417}
418
419template <floating_point Float>
420[[nodiscard]] constexpr auto conj(Float f) noexcept -> complex<Float>
421{
422 return complex<Float>(f);
423}
424
425template <integral Integer>
426[[nodiscard]] constexpr auto conj(Integer i) noexcept -> complex<double>
427{
428 return complex<double>(static_cast<double>(i));
429}
430
431template <typename T>
432[[nodiscard]] constexpr auto cos(complex<T> const& z) -> complex<T>
433{
434 auto const x = z.real();
435 auto const y = z.imag();
436 return {cos(x) * cosh(y), -sin(x) * sinh(y)};
437}
438
439template <typename T>
440[[nodiscard]] constexpr auto cosh(complex<T> const& z) -> complex<T>
441{
442 auto const x = z.real();
443 auto const y = z.imag();
444 return {cosh(x) * cos(y), sinh(x) * sin(y)};
445}
446
447template <typename T>
448[[nodiscard]] constexpr auto imag(complex<T> const& z) noexcept(noexcept(z.imag())) -> T
449{
450 return z.imag();
451}
452
453template <floating_point Float>
454[[nodiscard]] constexpr auto imag(Float /*f*/) noexcept -> Float
455{
456 return Float{};
457}
458
459template <integral Integer>
460[[nodiscard]] constexpr auto imag(Integer /*i*/) noexcept -> double
461{
462 return 0.0;
463}
464
465template <typename T>
466[[nodiscard]] constexpr auto log(complex<T> const& z) noexcept -> complex<T>
467{
468 return {etl::log(etl::abs(z)), etl::arg(z)};
469}
470
471template <typename T>
472[[nodiscard]] constexpr auto log10(complex<T> const& z) noexcept -> complex<T>
473{
474 return etl::log(z) / etl::log(T(10));
475}
476
477template <typename T>
478[[nodiscard]] constexpr auto norm(complex<T> const& z) noexcept -> T
479{
480 auto const x = z.real();
481 auto const y = z.imag();
482 return x * x + y * y;
483}
484
485template <floating_point Float>
486[[nodiscard]] constexpr auto norm(Float f) noexcept -> complex<Float>
487{
488 return etl::norm(etl::complex<Float>(f));
489}
490
491template <integral Integer>
492[[nodiscard]] constexpr auto norm(Integer i) noexcept -> complex<double>
493{
494 return etl::norm(etl::complex<double>(i));
495}
496
497template <typename T>
498[[nodiscard]] constexpr auto polar(T const& r, T const& theta = T()) noexcept -> etl::complex<T>
499{
500 return etl::complex<T>{r * etl::cos(theta), r * etl::sin(theta)};
501}
502
503template <typename T>
504[[nodiscard]] constexpr auto real(complex<T> const& z) noexcept(noexcept(z.real())) -> T
505{
506 return z.real();
507}
508
509template <floating_point Float>
510[[nodiscard]] constexpr auto real(Float f) noexcept -> Float
511{
512 return f;
513}
514
515template <integral Integer>
516[[nodiscard]] constexpr auto real(Integer i) noexcept -> double
517{
518 return static_cast<double>(i);
519}
520
521template <typename T>
522[[nodiscard]] constexpr auto sin(complex<T> const& z) -> complex<T>
523{
524 auto const x = z.real();
525 auto const y = z.imag();
526 return {
527 etl::sin(x) * etl::cosh(y),
528 etl::cos(x) * etl::sinh(y),
529 };
530}
531
532template <typename T>
533[[nodiscard]] constexpr auto sinh(complex<T> const& z) -> complex<T>
534{
535 auto const x = z.real();
536 auto const y = z.imag();
537 return {
538 etl::sinh(x) * etl::cos(y),
539 etl::cosh(x) * etl::sin(y),
540 };
541}
542
543template <typename T>
544[[nodiscard]] constexpr auto tan(complex<T> const& z) -> complex<T>
545{
546 return etl::sin(z) / etl::cos(z);
547}
548
549template <typename T>
550[[nodiscard]] constexpr auto tanh(complex<T> const& z) -> complex<T>
551{
552 return etl::sinh(z) / etl::cosh(z);
553}
554
555/// @}
556
557} // namespace etl
558
559#endif // TETL_COMPLEX_COMPLEX_HPP
Definition complex.hpp:354
constexpr auto operator""_i(unsigned long long d) -> complex< double >
Definition complex.hpp:371
constexpr auto operator""_il(unsigned long long d) -> complex< long double >
Definition complex.hpp:361
constexpr auto operator""_if(long double d) -> complex< float >
Definition complex.hpp:376
constexpr auto operator""_il(long double d) -> complex< long double >
Definition complex.hpp:356
constexpr auto operator""_if(unsigned long long d) -> complex< float >
Definition complex.hpp:381
constexpr auto operator""_i(long double d) -> complex< double >
Definition complex.hpp:366
Definition day.hpp:129
Definition adjacent_find.hpp:9
constexpr auto get(complex< X > const &z) noexcept -> X const &
Definition complex.hpp:127
constexpr auto log(complex< T > const &z) noexcept -> complex< T >
Definition complex.hpp:466
constexpr auto imag(Integer) noexcept -> double
Definition complex.hpp:460
constexpr auto arg(complex< T > const &z) noexcept -> T
Definition complex.hpp:396
constexpr auto arg(Float f) noexcept -> complex< Float >
Definition complex.hpp:402
constexpr auto sinh(complex< T > const &z) -> complex< T >
Definition complex.hpp:533
constexpr auto operator+(T const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:293
constexpr auto real(Integer i) noexcept -> double
Definition complex.hpp:516
constexpr auto operator-(complex< T > const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:299
constexpr auto tan(complex< T > const &z) -> complex< T >
Definition complex.hpp:544
constexpr auto get(complex< X > &z) noexcept -> X &
Definition complex.hpp:105
constexpr auto polar(T const &r, T const &theta=T()) noexcept -> etl::complex< T >
Definition complex.hpp:498
constexpr auto norm(complex< T > const &z) noexcept -> T
Definition complex.hpp:478
constexpr auto real(complex< T > const &z) noexcept(noexcept(z.real())) -> T
Definition complex.hpp:504
constexpr auto imag(Float) noexcept -> Float
Definition complex.hpp:454
constexpr auto operator+(complex< T > const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:281
constexpr auto sin(complex< T > const &z) -> complex< T >
Definition complex.hpp:522
constexpr auto norm(Integer i) noexcept -> complex< double >
Definition complex.hpp:492
constexpr auto operator-(complex< T > const &val) -> complex< T >
Definition complex.hpp:275
constexpr auto operator+(complex< T > const &val) -> complex< T >
Definition complex.hpp:269
constexpr auto operator/(T const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:347
constexpr auto real(Float f) noexcept -> Float
Definition complex.hpp:510
constexpr auto get(complex< X > const &&z) noexcept -> X const &&
Definition complex.hpp:138
constexpr auto operator-(T const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:311
constexpr auto imag(complex< T > const &z) noexcept(noexcept(z.imag())) -> T
Definition complex.hpp:448
constexpr auto operator/(complex< T > const &lhs, T const &rhs) -> complex< T >
Definition complex.hpp:341
constexpr auto abs(complex< T > const &z) -> T
Definition complex.hpp:390
constexpr auto operator/(complex< T > const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:335
constexpr auto cosh(complex< T > const &z) -> complex< T >
Definition complex.hpp:440
constexpr auto conj(Integer i) noexcept -> complex< double >
Definition complex.hpp:426
constexpr auto tanh(complex< T > const &z) -> complex< T >
Definition complex.hpp:550
constexpr auto cos(complex< T > const &z) -> complex< T >
Definition complex.hpp:432
constexpr auto conj(complex< T > const &z) noexcept -> complex< T >
Definition complex.hpp:414
constexpr auto operator*(T const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:329
constexpr auto norm(Float f) noexcept -> complex< Float >
Definition complex.hpp:486
constexpr auto conj(Float f) noexcept -> complex< Float >
Definition complex.hpp:420
constexpr auto operator*(complex< T > const &lhs, complex< T > const &rhs) -> complex< T >
Definition complex.hpp:317
constexpr auto log10(complex< T > const &z) noexcept -> complex< T >
Definition complex.hpp:472
constexpr auto arg(Integer i) noexcept -> complex< double >
Definition complex.hpp:408
constexpr auto get(complex< X > &&z) noexcept -> X &&
Definition complex.hpp:116
constexpr auto operator-(complex< T > const &lhs, T const &rhs) -> complex< T >
Definition complex.hpp:305
constexpr auto operator*(complex< T > const &lhs, T const &rhs) -> complex< T >
Definition complex.hpp:323
constexpr auto operator+(complex< T > const &lhs, T const &rhs) -> complex< T >
Definition complex.hpp:287
A complex number.
Definition complex.hpp:32
explicit(sizeof(X) > sizeof(T)) const expr complex(complex< X > const &other)
constexpr auto operator+=(complex< X > const &val) -> complex< T > &
Definition complex.hpp:225
constexpr auto operator*=(complex< X > const &val) -> complex< T > &
Definition complex.hpp:243
constexpr auto imag(T val) -> void
Definition complex.hpp:182
constexpr auto operator/=(T const &val) -> complex< T > &
Definition complex.hpp:217
constexpr auto operator/=(complex< X > const &val) -> complex< T > &
Definition complex.hpp:253
constexpr auto operator-=(T const &val) -> complex< T > &
Definition complex.hpp:203
constexpr auto imag() const -> T
Definition complex.hpp:176
constexpr complex(T const &re=T(), T const &im=T())
Definition complex.hpp:149
friend constexpr auto get(complex< X > &&) noexcept -> X &&
Definition complex.hpp:116
constexpr auto real(T val) -> void
Definition complex.hpp:170
friend constexpr auto operator==(complex const &lhs, T const &rhs) -> bool
Definition complex.hpp:82
friend constexpr auto get(complex< X > &) noexcept -> X &
Definition complex.hpp:105
constexpr auto operator=(complex< X > const &other) -> complex< T > &
friend constexpr auto operator==(complex const &lhs, complex const &rhs) -> bool
Definition complex.hpp:77
constexpr auto operator=(T const &val) -> complex< T > &
Definition complex.hpp:188
constexpr auto operator+=(T const &val) -> complex< T > &
Definition complex.hpp:196
friend constexpr auto get(complex< X > const &) noexcept -> X const &
Definition complex.hpp:127
constexpr auto real() const -> T
Definition complex.hpp:164
constexpr auto operator*=(T const &val) -> complex< T > &
Definition complex.hpp:210
friend constexpr auto get(complex< X > const &&) noexcept -> X const &&
Definition complex.hpp:138
constexpr auto operator-=(complex< X > const &val) -> complex< T > &
Definition complex.hpp:234
constexpr complex(complex const &other)=default
constexpr auto operator=(complex const &other) -> complex &=default
Definition integral_constant.hpp:11