dsplib 1.1.0
C++ DSP library for MATLAB-like coding
Loading...
Searching...
No Matches
types.h
1#pragma once
2
3#include <complex>
4#include <type_traits>
5#include <limits>
6#include <iosfwd>
7
8#include <dsplib/defs.h>
9
10#ifndef restrict
11#ifdef _MSC_VER
12#define restrict __restrict
13#else
14#define restrict __restrict__
15#endif
16#endif
17
18// fix for interger real (because 5+5i is not compiled, but 5.0+5i is OK)
19//-------------------------------------------------------------------------------------------------
20template<typename T>
21constexpr std::complex<T> operator+(const int& lhs, const std::complex<T>& rhs) {
22 return std::complex<T>(T(lhs)) + rhs;
23}
24
25template<typename T>
26constexpr std::complex<T> operator-(const int& lhs, const std::complex<T>& rhs) {
27 return std::complex<T>(T(lhs)) - rhs;
28}
29
30template<typename T>
31constexpr std::complex<T> operator+(const std::complex<T>& lhs, const int& rhs) {
32 return lhs + std::complex<T>(T(rhs));
33}
34
35template<typename T>
36constexpr std::complex<T> operator-(const std::complex<T>& lhs, const int& rhs) {
37 return lhs - std::complex<T>(T(rhs));
38}
39
40namespace dsplib {
41
42using namespace std::complex_literals;
43
44//-------------------------------------------------------------------------------------------------
45//base scalar type
46#ifdef DSPLIB_USE_FLOAT32
47using real_t = float;
48static_assert(sizeof(real_t) == 4);
49#else
50using real_t = double;
51static_assert(sizeof(real_t) == 8);
52#endif
53
54constexpr real_t pi = 3.141592653589793238463;
55constexpr real_t inf = std::numeric_limits<real_t>::infinity();
56
57struct cmplx_t;
58
59//Floating-point relative accuracy
60float eps(float v);
61double eps(double v);
62real_t eps();
63
64template<typename T>
66 : std::integral_constant<bool, std::is_same_v<T, std::complex<float>> || std::is_same_v<T, std::complex<double>> ||
67 std::is_same_v<T, std::complex<int>>>
68{};
69
70template<typename T>
71constexpr bool is_std_complex_v = is_std_complex<T>::value;
72
73template<typename T>
74struct is_complex : std::integral_constant<bool, is_std_complex<T>::value || std::is_same_v<T, cmplx_t>>
75{};
76
77template<typename T>
78constexpr bool is_complex_v = is_complex<T>::value;
79
80template<typename T>
81struct is_scalar : std::integral_constant<bool, std::is_arithmetic_v<T> || is_complex_v<T>>
82{};
83
84template<typename T>
85constexpr bool is_scalar_v = is_scalar<T>::value;
86
87template<typename T>
88using enable_scalar = std::enable_if<is_scalar_v<T>>;
89
90template<typename T>
91using enable_scalar_t = typename enable_scalar<T>::type;
92
93template<typename T, typename T2>
94using enable_convertible = std::enable_if<std::is_convertible_v<T, T2>>;
95
96template<typename T, typename T2>
97using enable_convertible_t = typename enable_convertible<T, T2>::type;
98
99//-------------------------------------------------------------------------------------------------
100//basic complex type
102{
103 constexpr cmplx_t(real_t vre = 0, real_t vim = 0)
104 : re{vre}
105 , im{vim} {
106 }
107
108 constexpr cmplx_t(const cmplx_t&) = default;
109
110 //scalar -> cmplx_t
111 template<typename T, std::enable_if_t<std::is_arithmetic_v<std::remove_reference_t<T>>>* = nullptr>
112 constexpr cmplx_t(const T& v)
113 : re{static_cast<real_t>(v)} {
114 }
115
116 //std::complex -> cmplx_t
117 template<typename T, std::enable_if_t<std::is_arithmetic_v<std::remove_reference_t<T>>>* = nullptr>
118 constexpr cmplx_t(const std::complex<T>& v)
119 : re{static_cast<real_t>(v.real())}
120 , im{static_cast<real_t>(v.imag())} {
121 }
122
123 //cmplx_t -> std::complex
124 template<typename T, std::enable_if_t<std::is_arithmetic_v<std::remove_reference_t<T>>>* = nullptr>
125 operator std::complex<T>() const {
126 return std::complex<T>(static_cast<T>(re), static_cast<T>(im));
127 }
128
129 real_t re{0};
130 real_t im{0};
131
132 cmplx_t& operator=(const cmplx_t&) = default;
133
134 const cmplx_t& operator+() const noexcept {
135 return *this;
136 }
137
138 cmplx_t operator-() const noexcept {
139 return {-re, -im};
140 }
141
142 cmplx_t& operator+=(const cmplx_t& rhs) noexcept {
143 *this = *this + rhs;
144 return *this;
145 }
146
147 cmplx_t& operator-=(const cmplx_t& rhs) noexcept {
148 *this = *this - rhs;
149 return *this;
150 }
151
152 cmplx_t& operator*=(const cmplx_t& rhs) noexcept {
153 *this = *this * rhs;
154 return *this;
155 }
156
157 cmplx_t& operator/=(const cmplx_t& rhs) noexcept {
158 *this = *this / rhs;
159 return *this;
160 }
161
162 constexpr cmplx_t operator+(const cmplx_t& rhs) const noexcept {
163 return {re + rhs.re, im + rhs.im};
164 }
165
166 constexpr cmplx_t operator-(const cmplx_t& rhs) const noexcept {
167 return {re - rhs.re, im - rhs.im};
168 }
169
170 constexpr cmplx_t operator*(const cmplx_t& rhs) const noexcept {
171 return {(re * rhs.re) - (im * rhs.im), (re * rhs.im) + (im * rhs.re)};
172 }
173
174 constexpr cmplx_t operator/(const cmplx_t& rhs) const noexcept {
175 return {((re * rhs.re) + (im * rhs.im)) / rhs.abs2(), ((rhs.re * im) - (re * rhs.im)) / rhs.abs2()};
176 }
177
178 //cmplx * scalar
179 cmplx_t& operator+=(const real_t& rhs) noexcept {
180 re += rhs;
181 return *this;
182 }
183
184 constexpr cmplx_t operator+(const real_t& rhs) const noexcept {
185 return {re + rhs, im};
186 }
187
188 cmplx_t& operator-=(const real_t& rhs) noexcept {
189 re -= rhs;
190 return *this;
191 }
192
193 constexpr cmplx_t operator-(const real_t& rhs) const noexcept {
194 return {re - rhs, im};
195 }
196
197 cmplx_t& operator*=(const real_t& rhs) noexcept {
198 re *= rhs;
199 im *= rhs;
200 return *this;
201 }
202
203 constexpr cmplx_t operator*(const real_t& rhs) const noexcept {
204 return {re * rhs, im * rhs};
205 }
206
207 cmplx_t& operator/=(const real_t& rhs) noexcept {
208 re = (re / rhs);
209 im = (im / rhs);
210 return *this;
211 }
212
213 constexpr cmplx_t operator/(const real_t& rhs) const noexcept {
214 return {re / rhs, im / rhs};
215 }
216
217 constexpr bool operator>(const cmplx_t& rhs) const noexcept {
218 return abs2() > rhs.abs2();
219 }
220
221 constexpr bool operator<(const cmplx_t& rhs) const noexcept {
222 return abs2() < rhs.abs2();
223 }
224
225 constexpr bool operator==(const cmplx_t& rhs) const noexcept {
226 return (re == rhs.re) && (im == rhs.im);
227 }
228
229 constexpr bool operator!=(const cmplx_t& rhs) const noexcept {
230 return !(*this == rhs);
231 }
232
233 [[nodiscard]] constexpr cmplx_t conj() const noexcept {
234 return {re, -im};
235 }
236
237 [[nodiscard]] constexpr real_t abs2() const noexcept {
238 return re * re + im * im;
239 }
240
241 friend std::ostream& operator<<(std::ostream& os, const cmplx_t& x);
242};
243
244//left oriented real * cmplx
245template<class T, class S_ = enable_scalar_t<T>, class C_ = enable_convertible_t<T, cmplx_t>>
246constexpr cmplx_t operator+(const T& lhs, const cmplx_t& rhs) {
247 return rhs + lhs;
248}
249
250template<class T, class S_ = enable_scalar_t<T>, class C_ = enable_convertible_t<T, cmplx_t>>
251constexpr cmplx_t operator-(const T& lhs, const cmplx_t& rhs) {
252 return {lhs - rhs.re, -rhs.im};
253}
254
255template<class T, class S_ = enable_scalar_t<T>, class C_ = enable_convertible_t<T, cmplx_t>>
256constexpr cmplx_t operator*(const T& lhs, const cmplx_t& rhs) {
257 return rhs * lhs;
258}
259
260template<class T, class S_ = enable_scalar_t<T>, class C_ = enable_convertible_t<T, cmplx_t>>
261constexpr cmplx_t operator/(const T& lhs, const cmplx_t& rhs) {
262 return cmplx_t(lhs) / rhs;
263}
264
265static_assert(std::is_trivially_copyable<real_t>(), "type must be trivially copyable");
266static_assert(std::is_trivially_copyable<cmplx_t>(), "type must be trivially copyable");
267
268} // namespace dsplib
Definition types.h:102
Definition types.h:75
Definition types.h:82
Definition types.h:68