8#include <dsplib/defs.h>
12#define restrict __restrict
14#define restrict __restrict__
21constexpr std::complex<T> operator+(
const int& lhs,
const std::complex<T>& rhs) {
22 return std::complex<T>(T(lhs)) + rhs;
26constexpr std::complex<T> operator-(
const int& lhs,
const std::complex<T>& rhs) {
27 return std::complex<T>(T(lhs)) - rhs;
31constexpr std::complex<T> operator+(
const std::complex<T>& lhs,
const int& rhs) {
32 return lhs + std::complex<T>(T(rhs));
36constexpr std::complex<T> operator-(
const std::complex<T>& lhs,
const int& rhs) {
37 return lhs - std::complex<T>(T(rhs));
42using namespace std::complex_literals;
46#ifdef DSPLIB_USE_FLOAT32
48static_assert(
sizeof(real_t) == 4);
51static_assert(
sizeof(real_t) == 8);
54constexpr real_t pi = 3.141592653589793238463;
55constexpr real_t inf = std::numeric_limits<real_t>::infinity();
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>>>
74struct is_complex : std::integral_constant<bool, is_std_complex<T>::value || std::is_same_v<T, cmplx_t>>
81struct is_scalar : std::integral_constant<bool, std::is_arithmetic_v<T> || is_complex_v<T>>
88using enable_scalar = std::enable_if<is_scalar_v<T>>;
91using enable_scalar_t =
typename enable_scalar<T>::type;
93template<
typename T,
typename T2>
94using enable_convertible = std::enable_if<std::is_convertible_v<T, T2>>;
96template<
typename T,
typename T2>
97using enable_convertible_t =
typename enable_convertible<T, T2>::type;
103 constexpr cmplx_t(real_t vre = 0, real_t vim = 0)
111 template<
typename T, std::enable_if_t<std::is_arithmetic_v<std::remove_reference_t<T>>>* =
nullptr>
113 : re{
static_cast<real_t
>(v)} {
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())} {
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));
134 const cmplx_t& operator+()
const noexcept {
138 cmplx_t operator-()
const noexcept {
163 return {re + rhs.re, im + rhs.im};
167 return {re - rhs.re, im - rhs.im};
171 return {(re * rhs.re) - (im * rhs.im), (re * rhs.im) + (im * rhs.re)};
175 return {((re * rhs.re) + (im * rhs.im)) / rhs.abs2(), ((rhs.re * im) - (re * rhs.im)) / rhs.abs2()};
179 cmplx_t& operator+=(
const real_t& rhs)
noexcept {
184 constexpr cmplx_t operator+(
const real_t& rhs)
const noexcept {
185 return {re + rhs, im};
188 cmplx_t& operator-=(
const real_t& rhs)
noexcept {
193 constexpr cmplx_t operator-(
const real_t& rhs)
const noexcept {
194 return {re - rhs, im};
197 cmplx_t& operator*=(
const real_t& rhs)
noexcept {
203 constexpr cmplx_t operator*(
const real_t& rhs)
const noexcept {
204 return {re * rhs, im * rhs};
207 cmplx_t& operator/=(
const real_t& rhs)
noexcept {
213 constexpr cmplx_t operator/(
const real_t& rhs)
const noexcept {
214 return {re / rhs, im / rhs};
217 constexpr bool operator>(
const cmplx_t& rhs)
const noexcept {
218 return abs2() > rhs.abs2();
221 constexpr bool operator<(
const cmplx_t& rhs)
const noexcept {
222 return abs2() < rhs.abs2();
225 constexpr bool operator==(
const cmplx_t& rhs)
const noexcept {
226 return (re == rhs.re) && (im == rhs.im);
229 constexpr bool operator!=(
const cmplx_t& rhs)
const noexcept {
230 return !(*
this == rhs);
233 [[nodiscard]]
constexpr cmplx_t conj()
const noexcept {
237 [[nodiscard]]
constexpr real_t abs2()
const noexcept {
238 return re * re + im * im;
241 friend std::ostream& operator<<(std::ostream& os,
const cmplx_t& x);
245template<
class T,
class S_ = enable_scalar_t<T>,
class C_ = enable_convertible_t<T, cmplx_t>>
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};
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) {
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;
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");