MathLib
Loading...
Searching...
No Matches
Complex.hpp
Go to the documentation of this file.
1#pragma once
2
5#include <Math/math/Angle.hpp>
6#include <cassert>
7#include <cmath>
8#include <complex>
9#include <concepts>
10#include <type_traits>
11
20namespace Math
21{
22
30template <std::floating_point T>
32{
33public:
37 using value_type = T;
39
43 constexpr BasicComplex() = default;
44 constexpr BasicComplex(T real_number) : _real(real_number) { }
45 constexpr BasicComplex(T real_part, T imaginary_part) : _real(real_part), _imaginary(imaginary_part) { }
46 constexpr BasicComplex(BasicRadian<T> real_part, BasicRadian<T> imaginary_part)
47 :
48 _real( real_part.value() ),
49 _imaginary( imaginary_part.value() )
50 {
51 }
52 constexpr BasicComplex(std::complex<T> c) : _real( std::real(c) ), _imaginary( std::imag(c) ) { }
54
59 constexpr static BasicComplex<T> identity() { return BasicComplex{ T{1}, T{} }; }
60
62 constexpr static BasicComplex<T> zero() { return BasicComplex{}; }
63 constexpr static BasicComplex<T> unit_real() { return identity(); }
64 constexpr static BasicComplex<T> unit_i() { return BasicComplex{ T{}, T{1} }; }
66
67 constexpr BasicComplex<T> conjugate() const
68 {
69 return BasicComplex<T>{ _real, -_imaginary };
70 }
71
73 BasicComplex<T> pow(T exponent) const
74 {
75 // NOTE: Because this is a template function, conversion operators are not
76 // considered. Thus, we directly call this->asStdComplex().
77 return std::pow( this->asStdComplex(), exponent );
78 }
79
80 BasicComplex<T> pow(int exponent) const
81 {
82 return std::pow( this->asStdComplex(), exponent );
83 }
84
86 {
87 return std::pow( this->asStdComplex(), exponent.asStdComplex() );
88 }
89
98 {
99 return std::exp( this->asStdComplex() );
100 }
101
108 {
109 return std::log( this->asStdComplex() );
110 }
111
116 {
117 return std::log10( this->asStdComplex() );
118 }
119
120 T normSquared() const { return accumulate(*this * conjugate()); }
121 T norm() const { return std::sqrt( normSquared() ); }
122
123 T magnitudeSquared() const { return normSquared(); }
124 T magnitude() const { return norm(); }
125
126 constexpr BasicComplex<T> normalized() const
127 {
128 assert( BasicComplex<T>{*this / magnitude()}.isUnit() ); // Verify that we actually return a unit-length BasicComplex
129
130 return *this / this->magnitude();
131 }
132
134
136 {
137 return atan2( BasicRadian<T>( imaginary() ), BasicRadian<T>( real() ) );
138 }
139
143 constexpr const T &real() const { return _real; }
144 constexpr void real(T r) { _real = r; }
145
146 constexpr const T &i() const { return _imaginary; }
147 constexpr void i(T r) { _imaginary = r; }
148
150 constexpr const T &imaginary() const { return _imaginary; }
151 constexpr void imaginary(T r) { _imaginary = r; }
153
154 bool isUnit() const { return approximately_equal_to( magnitude(), T{1} ); }
155 bool isUnit(T tolerance) const { return approximately_equal_to( magnitude(), T{1}, tolerance ); }
156
157 bool isZero() const { return approximately_equal_to( magnitude(), T{} ); }
158 bool isZero(T tolerance) const { return approximately_equal_to( magnitude(), T{}, tolerance ); }
159
160 // Checks if the real() part is 0
161 bool isPure() const { return approximately_equal_to(real(), T{}); }
162
166 bool isNaN() const
167 {
168 return std::isnan(_real) || std::isnan(_imaginary);
169 }
170 bool isInf() const
171 {
172 return std::isinf(_real) || std::isinf(_imaginary);
173 }
175
189 constexpr static BasicComplex<T> make_pure(T i) { return BasicComplex<T>{ T{}, i }; }
190
191 constexpr static BasicComplex<T> encode_point(T x, T y) { return BasicComplex<T>{ x, y }; }
192
201 {
202 return { cos( radians ), sin( radians ) };
203 }
205
206 constexpr std::complex<T> asStdComplex() const { return std::complex<T>{ _real, _imaginary }; }
207
211 operator std::complex<T>() const { return std::complex<T>{ _real, _imaginary }; }
213private:
214 T _real{};
215 T _imaginary{};
216
231 friend constexpr bool operator ==(const BasicComplex<T> &left, const BasicComplex<T> &right)
232 {
233 return approximately_equal_to(left, right);
234 }
235
246 template <std::floating_point OT = T>
247 friend constexpr bool approximately_equal_to(const BasicComplex<T> &value_to_test,
248 const BasicComplex<T> &value_it_should_be,
249 OT tolerance = OT{0.0002})
250 {
251 return approximately_equal_to(value_to_test.real(), value_it_should_be.real(), tolerance) &&
252 approximately_equal_to(value_to_test.imaginary(), value_it_should_be.imaginary(), tolerance);
253 }
255
266 friend constexpr BasicComplex<T> operator *(const BasicComplex<T> &left, const BasicComplex<T> &right)
267 {
268 return { left.real() * right.real() - left.imaginary() * right.imaginary(),
269 left.real() * right.imaginary() + left.imaginary() * right.real() };
270 }
271
272 template <std::floating_point OT>
273 friend constexpr BasicComplex<T> operator *(const BasicComplex<T> &complex, OT scalar)
274 {
275 return { complex.real() * T(scalar), complex.imaginary() * T(scalar) };
276 }
277
278 friend constexpr BasicComplex<T> operator /(const BasicComplex<T> &left, const BasicComplex<T> &right)
279 {
280 return left * right.inverse();
281 }
282
283 template <std::floating_point OT>
284 friend constexpr BasicComplex<T> operator /(const BasicComplex<T> &complex, OT scalar)
285 {
286 return { complex.real() / T(scalar),
287 complex.imaginary() / T(scalar) };
288 }
289
290 friend constexpr BasicComplex<T> operator +(const BasicComplex<T> &left, const BasicComplex<T> &right)
291 {
292 return { left.real() + right.real(),
293 left.imaginary() + right.imaginary() };
294 }
295
296 template <std::floating_point OT>
297 friend constexpr BasicComplex<T> operator +(const BasicComplex<T> &complex, OT scalar)
298 {
299 return { complex.real() + scalar, complex.imaginary() };
300 }
301
302 friend constexpr BasicComplex<T> operator -(const BasicComplex<T> &left, const BasicComplex<T> &right)
303 {
304 return { left.real() - right.real(),
305 left.imaginary() - right.imaginary() };
306 }
307
308 template <std::floating_point OT>
309 friend constexpr BasicComplex<T> operator -(const BasicComplex<T> &complex, OT scalar)
310 {
311 return { complex.real() - scalar, complex.imaginary() };
312 }
313
314 friend constexpr BasicComplex<T> operator -(const BasicComplex<T> &q)
315 {
316 return { -q.real(), -q.imaginary() };
317 }
320
338 template <std::floating_point OT = T>
339 friend bool check_if_equal(const BasicComplex<T> &input,
340 const BasicComplex<T> &near_to,
341 OT tolerance = OT{0.0002})
342 {
343 if (!approximately_equal_to(input, near_to, tolerance))
344 {
345 auto diff{ near_to - input };
346
347 std::cout << std::format("input: {} is not equal to near_to: {} within tolerance: {}. Difference is {} .",
348 format(input),
349 format(near_to),
350 tolerance,
351 format(near_to - input))
352 << std::endl;
353 return false;
354 }
355 return true;
356 }
357
366 template <std::floating_point OT = T>
367 friend bool check_if_not_equal(const BasicComplex<T> &input,
368 const BasicComplex<T> &near_to,
369 OT tolerance = OT{0.0002})
370 {
371 if (approximately_equal_to(input, near_to, tolerance))
372 {
373 auto diff{ near_to - input };
374
375 std::cout << std::format("input: {} is equal to near_to: {} within tolerance: {}. Difference is {} .",
376 format(input),
377 format(near_to),
378 tolerance,
379 format(near_to - input))
380 << std::endl;
381 return false;
382 }
383 return true;
384 }
387
405 template <std::floating_point OT = T>
406 friend void CHECK_IF_EQUAL(const BasicComplex<T> &input,
407 const BasicComplex<T> &near_to,
408 OT tolerance = OT{0.0002})
409 {
410 assert( check_if_equal(input, near_to, tolerance) );
411 }
412
421 template <std::floating_point OT = T>
422 friend void CHECK_IF_NOT_EQUAL(const BasicComplex<T> &input,
423 const BasicComplex<T> &near_to,
424 OT tolerance = OT{0.0002})
425 {
426 assert( check_if_not_equal(input, near_to, tolerance) );
427 }
428
438 template <std::floating_point OT = T>
439 friend void CHECK_IF_ZERO(const BasicComplex<T> &input, OT tolerance = OT{0.0002})
440 {
441 assert( check_if_equal(input, BasicComplex<T>::zero(), tolerance));
442 }
445
458 friend constexpr T dot(const BasicComplex<T> &left, const BasicComplex<T> &right)
459 {
460 return left.real() * right.real() +
461 left.imaginary() * right.imaginary();
462 }
463
464 friend constexpr T dot_normalized(const BasicComplex<T> &left, const BasicComplex<T> &right)
465 {
466 return ( left.real() * right.real() +
467 left.imaginary() * right.imaginary() ) / (left.magnitude() * right.magnitude());
468 }
469
486 const BasicComplex<T> &encoded_point)
487 {
488 assert( rotation.isUnit() );
489
490 return rotation * encoded_point;
491 }
492
498 friend constexpr BasicComplex<T> compose_rotations(const BasicComplex<T> &rotation_1,
499 const BasicComplex<T> &rotation_2)
500 {
501 return rotation_2 * rotation_1;
502 }
503
510 friend constexpr BasicComplex<T> normalized(const BasicComplex<T> &input)
511 {
512 return input.normalized();
513 }
514
519 friend constexpr BasicRadian<T> arg(const BasicComplex<T> &input)
520 {
521 return input.angle().value();
522 }
523
532 {
533 return std::polar( m, angle.value() );
534 }
535
542 friend constexpr T accumulate(const BasicComplex<T> &input)
543 {
544 return T{input.real() + input.i()};
545 }
546
553 friend constexpr BasicComplex<T> slerp(const BasicComplex<T> &begin,
554 const BasicComplex<T> &end,
555 T percent)
556 {
557 BasicComplex<T> combined{ begin.conjugate() * end };
558 BasicComplex<T> powered{ combined.pow(percent) };
559 BasicComplex<T> result{ begin * powered };
560
561 return result;
562 }
563
564 friend std::string format(const BasicComplex<T> &input)
565 {
566 return std::format("[real: {}, i: {}]", input.real(), input.i() );
567 }
568
573 friend constexpr BasicComplex<T> conjugate(const BasicComplex<T> &input)
574 {
575 return input.conjugate();
576 }
577
582 friend constexpr BasicComplex<T> log(const BasicComplex<T> &input)
583 {
584 return input.log();
585 }
586
591 friend constexpr BasicComplex<T> log10(const BasicComplex<T> &input)
592 {
593 return input.log10();
594 }
595
601 {
602 return input.exp();
603 }
604
610 friend BasicComplex<T> pow(const BasicComplex<T> &input, T p)
611 {
612 return input.pow( p );
613 }
614
615 friend BasicComplex<T> pow(const BasicComplex<T> &input, int p)
616 {
617 return input.pow( p );
618 }
619
620 friend BasicComplex<T> pow(const BasicComplex<T> &input, const BasicComplex<T> &p)
621 {
622 return input.pow( p );
623 }
625
632 {
633 return std::sin( c.asStdComplex() );
634 }
635
637 {
638 return std::cos( c.asStdComplex() );
639 }
640
642 {
643 return std::tan( c.asStdComplex() );
644 }
645
647 {
648 return std::asin( c.asStdComplex() );
649 }
650
652 {
653 return std::acos( c.asStdComplex() );
654 }
655
657 {
658 return std::atan( c.asStdComplex() );
659 }
660
662 {
663 return std::sinh( c.asStdComplex() );
664 }
665
667 {
668 return std::cosh( c.asStdComplex() );
669 }
670
672 {
673 return std::tanh( c.asStdComplex() );
674 }
675
677 {
678 return std::asinh( c.asStdComplex() );
679 }
680
682 {
683 return std::acosh( c.asStdComplex() );
684 }
685
687 {
688 return std::atanh( c.asStdComplex() );
689 }
691
693};
694
713
714}
friend BasicComplex< T > acosh(BasicComplex< T > c)
Definition Complex.hpp:681
T magnitudeSquared() const
Definition Complex.hpp:123
friend BasicComplex< T > atan(BasicComplex< T > c)
Definition Complex.hpp:656
constexpr const T & i() const
Definition Complex.hpp:146
BasicComplex< T > log() const
Definition Complex.hpp:107
BasicComplex< T > pow(BasicComplex< T > exponent) const
Definition Complex.hpp:85
bool isNaN() const
Definition Complex.hpp:166
friend BasicComplex< T > asin(BasicComplex< T > c)
Definition Complex.hpp:646
friend BasicComplex< T > tanh(BasicComplex< T > c)
Definition Complex.hpp:671
constexpr BasicComplex(std::complex< T > c)
Conversion from std::complex.
Definition Complex.hpp:52
constexpr BasicComplex(T real_number)
Constructs a BasicComplex equivalent to the given real number.
Definition Complex.hpp:44
constexpr void imaginary(T r)
Definition Complex.hpp:151
friend constexpr BasicComplex< T > log(const BasicComplex< T > &input)
Definition Complex.hpp:582
bool isZero() const
Definition Complex.hpp:157
BasicRadian< T > angle() const
Definition Complex.hpp:135
friend BasicComplex< T > pow(const BasicComplex< T > &input, const BasicComplex< T > &p)
Definition Complex.hpp:620
friend constexpr BasicComplex< T > log10(const BasicComplex< T > &input)
Definition Complex.hpp:591
constexpr BasicComplex< T > normalized() const
Definition Complex.hpp:126
constexpr void real(T r)
Definition Complex.hpp:144
bool isZero(T tolerance) const
Definition Complex.hpp:158
friend std::string format(const BasicComplex< T > &input)
Definition Complex.hpp:564
constexpr const T & imaginary() const
Extracts the imaginary part of a BasicComplex.
Definition Complex.hpp:150
friend constexpr T dot_normalized(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:464
friend constexpr BasicComplex< T > conjugate(const BasicComplex< T > &input)
Definition Complex.hpp:573
constexpr BasicComplex()=default
friend BasicComplex< T > pow(const BasicComplex< T > &input, T p)
Definition Complex.hpp:610
friend constexpr BasicComplex< T > passively_rotate_encoded_point(const BasicComplex< T > &rotation, const BasicComplex< T > &encoded_point)
Definition Complex.hpp:485
constexpr std::complex< T > asStdComplex() const
Definition Complex.hpp:206
friend constexpr BasicComplex< T > polar(T m, BasicRadian< T > angle=BasicRadian< T >{})
Definition Complex.hpp:531
friend constexpr BasicRadian< T > arg(const BasicComplex< T > &input)
Definition Complex.hpp:519
friend BasicComplex< T > acos(BasicComplex< T > c)
Definition Complex.hpp:651
friend BasicComplex< T > asinh(BasicComplex< T > c)
Definition Complex.hpp:676
constexpr BasicComplex(T real_part, T imaginary_part)
Definition Complex.hpp:45
T normSquared() const
Definition Complex.hpp:120
friend BasicComplex< T > exp(const BasicComplex< T > &input)
Definition Complex.hpp:600
friend BasicComplex< T > tan(BasicComplex< T > c)
Definition Complex.hpp:641
friend BasicComplex< T > sin(BasicComplex< T > c)
Definition Complex.hpp:631
static constexpr BasicComplex< T > zero()
BasicComplex representation of the real number 0.
Definition Complex.hpp:62
friend constexpr bool approximately_equal_to(const BasicComplex< T > &value_to_test, const BasicComplex< T > &value_it_should_be, OT tolerance=OT{0.0002})
Definition Complex.hpp:247
T magnitude() const
Definition Complex.hpp:124
bool isPure() const
Definition Complex.hpp:161
static constexpr BasicComplex< T > make_rotation(BasicRadian< T > radians)
Definition Complex.hpp:200
static constexpr BasicComplex< T > identity()
BasicComplex representation of the real number 1.
Definition Complex.hpp:59
bool isUnit() const
Definition Complex.hpp:154
friend BasicComplex< T > sinh(BasicComplex< T > c)
Definition Complex.hpp:661
static constexpr BasicComplex< T > unit_i()
Definition Complex.hpp:64
friend BasicComplex< T > cosh(BasicComplex< T > c)
Definition Complex.hpp:666
friend constexpr BasicComplex< T > compose_rotations(const BasicComplex< T > &rotation_1, const BasicComplex< T > &rotation_2)
Definition Complex.hpp:498
friend constexpr bool operator==(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:231
friend BasicComplex< T > atanh(BasicComplex< T > c)
Definition Complex.hpp:686
BasicComplex< T > exp() const
Definition Complex.hpp:97
BasicComplex< T > pow(int exponent) const
Definition Complex.hpp:80
constexpr void i(T r)
Definition Complex.hpp:147
friend BasicComplex< T > cos(BasicComplex< T > c)
Definition Complex.hpp:636
static constexpr BasicComplex< T > make_pure(T i)
Definition Complex.hpp:189
constexpr BasicComplex< T > conjugate() const
Definition Complex.hpp:67
constexpr const T & real() const
Definition Complex.hpp:143
static constexpr BasicComplex< T > encode_point(T x, T y)
Definition Complex.hpp:191
static constexpr BasicComplex< T > unit_real()
Definition Complex.hpp:63
friend constexpr T dot(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:458
friend constexpr T accumulate(const BasicComplex< T > &input)
Definition Complex.hpp:542
friend constexpr BasicComplex< T > slerp(const BasicComplex< T > &begin, const BasicComplex< T > &end, T percent)
Definition Complex.hpp:553
bool isUnit(T tolerance) const
Definition Complex.hpp:155
BasicComplex< T > log10() const
Definition Complex.hpp:115
friend constexpr BasicComplex< T > normalized(const BasicComplex< T > &input)
Definition Complex.hpp:510
BasicComplex< T > pow(T exponent) const
Computes this BasicComplex raised to a real power.
Definition Complex.hpp:73
constexpr BasicComplex(BasicRadian< T > real_part, BasicRadian< T > imaginary_part)
Definition Complex.hpp:46
T value_type
The underlying implementation type.
Definition Complex.hpp:37
BasicComplex< T > inverse() const
Definition Complex.hpp:133
bool isInf() const
Definition Complex.hpp:170
friend BasicComplex< T > pow(const BasicComplex< T > &input, int p)
Definition Complex.hpp:615
friend void CHECK_IF_NOT_EQUAL(const BasicComplex< T > &input, const BasicComplex< T > &near_to, OT tolerance=OT{0.0002})
Definition Complex.hpp:422
friend void CHECK_IF_EQUAL(const BasicComplex< T > &input, const BasicComplex< T > &near_to, OT tolerance=OT{0.0002})
Definition Complex.hpp:406
friend void CHECK_IF_ZERO(const BasicComplex< T > &input, OT tolerance=OT{0.0002})
Definition Complex.hpp:439
friend bool check_if_equal(const BasicComplex< T > &input, const BasicComplex< T > &near_to, OT tolerance=OT{0.0002})
Definition Complex.hpp:339
friend bool check_if_not_equal(const BasicComplex< T > &input, const BasicComplex< T > &near_to, OT tolerance=OT{0.0002})
Definition Complex.hpp:367
friend constexpr BasicComplex< T > operator+(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:290
friend constexpr BasicComplex< T > operator/(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:278
friend constexpr BasicComplex< T > operator*(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:266
friend constexpr BasicComplex< T > operator-(const BasicComplex< T > &left, const BasicComplex< T > &right)
Definition Complex.hpp:302
Definition Angle.hpp:16