%PDF- %PDF-
| Direktori : /usr/include/xsimd/math/ |
| Current File : //usr/include/xsimd/math/xsimd_math_complex.hpp |
/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
* Martin Renou *
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#ifndef XSIMD_MATH_COMPLEX_HPP
#define XSIMD_MATH_COMPLEX_HPP
#include "../types/xsimd_complex_base.hpp"
#include "xsimd_basic_math.hpp"
#include "xsimd_exponential.hpp"
#include "xsimd_hyperbolic.hpp"
#include "xsimd_logarithm.hpp"
#include "xsimd_power.hpp"
#include "xsimd_trigonometric.hpp"
namespace xsimd
{
template <class X>
real_batch_type_t<X> real(const simd_base<X>& z);
template <class X>
real_batch_type_t<X> imag(const simd_base<X>& z);
template <class X>
real_batch_type_t<X> arg(const simd_base<X>& z);
template <class X>
batch_type_t<X> conj(const simd_base<X>& z);
template <class X>
real_batch_type_t<X> norm(const simd_base<X>& rhs);
template <class X>
batch_type_t<X> proj(const simd_base<X>& rhs);
namespace detail
{
/********
* sign *
********/
template <class T, std::size_t N>
inline batch<T, N> sign_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
auto rz = z.real();
auto iz = z.imag();
return select(rz != r_type(0.),
b_type(sign(rz)),
b_type(sign(iz)));
}
template <class T, std::size_t N>
struct sign_impl<batch<std::complex<T>, N>, false>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return sign_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct sign_impl<batch<xtl::xcomplex<T, T, i3ec>, N>, false>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return sign_complex_impl(z);
}
};
#endif
/*******
* exp *
*******/
template <class T, std::size_t N>
inline batch<T, N> exp_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
r_type icos, isin;
sincos(z.imag(), isin, icos);
return exp(z.real()) * batch<T, N>(icos, isin);
}
template <class T, std::size_t N>
struct exp_kernel<batch<std::complex<T>, N>, exp_tag, std::complex<T>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return exp_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct exp_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>, exp_tag, xtl::xcomplex<T, T, i3ec>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return exp_complex_impl(z);
}
};
#endif
/*********
* expm1 *
*********/
template <class T, std::size_t N>
inline batch<T, N> expm1_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
r_type isin = sin(z.imag());
r_type rem1 = expm1(z.real());
r_type re = rem1 + r_type(1.);
r_type si = sin(z.imag() * r_type(0.5));
return batch<T, N>(rem1 - r_type(2.) * re * si * si, re * isin);
}
template <class T, std::size_t N>
struct expm1_kernel<batch<std::complex<T>, N>, std::complex<T>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return expm1_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct expm1_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>, xtl::xcomplex<T, T, i3ec>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return expm1_complex_impl(z);
}
};
#endif
/*******
* log *
*******/
template <class T, std::size_t N>
inline batch<T, N> log_complex_impl(const batch<T, N>& z)
{
return batch<T, N>(log(abs(z)), atan2(z.imag(), z.real()));
}
template <class T, std::size_t N>
struct log_kernel<batch<std::complex<T>, N>, std::complex<T>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return log_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct log_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>, xtl::xcomplex<T, T, i3ec>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return log_complex_impl(z);
}
};
#endif
/*********************
* logN_complex_impl *
*********************/
template <class T, std::size_t N>
inline batch<T, N> logN_complex_impl(const batch<T, N>& z, typename batch<T, N>::real_value_type base)
{
using b_type = batch<T, N>;
using rv_type = typename b_type::real_value_type;
return log(z) / b_type(rv_type(base));
}
/********
* log2 *
********/
template <class T, std::size_t N>
struct log2_kernel<batch<std::complex<T>, N>, std::complex<T>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return logN_complex_impl(z, std::log(2));
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct log2_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>, xtl::xcomplex<T, T, i3ec>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return logN_complex_impl(z, std::log(2));
}
};
#endif
/*********
* log10 *
*********/
template <class T, std::size_t N>
struct log10_kernel<batch<std::complex<T>, N>, std::complex<T>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return logN_complex_impl(z, std::log(10));
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct log10_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>, xtl::xcomplex<T, T, i3ec>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return logN_complex_impl(z, std::log(10));
}
};
#endif
/*********
* log1p *
*********/
template <class T, std::size_t N>
inline batch<T, N> log1p_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
b_type u = b_type(1.) + z;
b_type logu = log(u);
return select(u == b_type(1.),
z,
select(u.real() <= r_type(0.),
logu,
logu * z / (u - b_type(1.))));
}
template <class T, std::size_t N>
struct log1p_kernel<batch<std::complex<T>, N>, std::complex<T>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return log1p_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct log1p_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>, xtl::xcomplex<T, T, i3ec>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return log1p_complex_impl(z);
}
};
#endif
/*******
* pow *
*******/
template <class T, std::size_t N>
inline batch<T, N> pow_complex_impl(const batch<T, N>& a, const batch<T, N>& z)
{
using cplx_batch = batch<T, N>;
using real_batch = typename cplx_batch::real_batch;
real_batch absa = abs(a);
real_batch arga = arg(a);
real_batch x = z.real();
real_batch y = z.imag();
real_batch r = pow(absa, x);
real_batch theta = x * arga;
real_batch ze = zero<real_batch>();
auto cond = (y == ze);
r = select(cond, r, r * exp(-y * arga));
theta = select(cond, theta, theta + y * log(absa));
return select(absa == ze, cplx_batch(ze), cplx_batch(r * cos(theta), r * sin(theta)));
}
template <class T, std::size_t N>
struct pow_kernel<batch<std::complex<T>, N>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& a, const batch_type& z)
{
return pow_complex_impl(a, z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct pow_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& a, const batch_type& z)
{
return pow_complex_impl(a, z);
}
};
#endif
/*********
* trigo *
*********/
template <class T, std::size_t N>
inline void sincos_complex_impl(const batch<T, N>& z, batch<T, N>& si, batch<T, N>& co)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
r_type rcos = cos(z.real());
r_type rsin = sin(z.real());
r_type icosh = cosh(z.imag());
r_type isinh = sinh(z.imag());
si = b_type(rsin * icosh, rcos * isinh);
co = b_type(rcos * icosh, -rsin * isinh);
}
template <class T, std::size_t N>
inline batch<T, N> sin_complex_impl(const batch<T, N>& z)
{
return batch<T, N>(sin(z.real()) * cosh(z.imag()), cos(z.real()) * sinh(z.imag()));
}
template <class T, std::size_t N>
inline batch<T, N> cos_complex_impl(const batch<T, N>& z)
{
return batch<T, N>(cos(z.real()) * cosh(z.imag()), -sin(z.real()) * sinh(z.imag()));
}
template <class T, std::size_t N>
inline batch<T, N> tan_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
r_type d = cos(2 * z.real()) + cosh(2 * z.imag());
b_type winf(infinity<r_type>(), infinity<r_type>());
r_type wreal = sin(2 * z.real()) / d;
r_type wimag = sinh(2 * z.imag());
b_type wres = select(xsimd::isinf(wimag), b_type(wreal, r_type(1.)), b_type(wreal, wimag / d));
return select(d == r_type(0.), winf, wres);
}
template <class T, std::size_t N>
struct trigo_kernel<batch<std::complex<T>, N>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type sin(const batch_type& z)
{
return sin_complex_impl(z);
}
static inline batch_type cos(const batch_type& z)
{
return cos_complex_impl(z);
}
static inline batch_type tan(const batch_type& z)
{
return tan_complex_impl(z);
}
static inline void sincos(const batch_type& z, batch_type& si, batch_type& co)
{
return sincos_complex_impl(z, si, co);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct trigo_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type sin(const batch_type& z)
{
return sin_complex_impl(z);
}
static inline batch_type cos(const batch_type& z)
{
return cos_complex_impl(z);
}
static inline batch_type tan(const batch_type& z)
{
return tan_complex_impl(z);
}
static inline void sincos(const batch_type& z, batch_type& si, batch_type& co)
{
return sincos_complex_impl(z, si, co);
}
};
#endif
/************
* invtrigo *
************/
template <class T, std::size_t N>
batch<T, N> asin_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
r_type x = z.real();
r_type y = z.imag();
b_type ct(-y, x);
b_type zz(r_type(1.) - (x - y) * (x + y), -2 * x * y);
zz = log(ct + sqrt(zz));
b_type resg(zz.imag(), -zz.real());
return select(y == r_type(0.),
select(fabs(x) > r_type(1.),
b_type(pio2<r_type>(), r_type(0.)),
b_type(asin(x), r_type(0.))),
resg);
}
template <class T, std::size_t N>
batch<T, N> acos_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
b_type tmp = asin_complex_impl(z);
return b_type(pio2<r_type>() - tmp.real(), -tmp.imag());
}
template <class T, std::size_t N>
batch<T, N> atan_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
using r_type = typename b_type::real_batch;
r_type x = z.real();
r_type y = z.imag();
r_type x2 = x * x;
r_type one = r_type(1.);
r_type a = one - x2 - (y * y);
r_type w = 0.5 * atan2(2. * x, a);
r_type num = y + one;
num = x2 + num * num;
r_type den = y - one;
den = x2 + den * den;
b_type res = select((x == r_type(0.)) && (y == r_type(1.)),
b_type(r_type(0.), infinity<r_type>()),
b_type(w, 0.25 * log(num / den)));
return res;
}
template <class T, std::size_t N>
struct invtrigo_kernel<batch<std::complex<T>, N>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type asin(const batch_type& z)
{
return asin_complex_impl(z);
}
static inline batch_type acos(const batch_type& z)
{
return acos_complex_impl(z);
}
static inline batch_type atan(const batch_type& z)
{
return atan_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct invtrigo_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type asin(const batch_type& z)
{
return asin_complex_impl(z);
}
static inline batch_type acos(const batch_type& z)
{
return acos_complex_impl(z);
}
static inline batch_type atan(const batch_type& z)
{
return atan_complex_impl(z);
}
};
#endif
/********
* sinh *
********/
template <class T, std::size_t N>
inline batch<T, N> sinh_complex_impl(const batch<T, N>& z)
{
auto x = z.real();
auto y = z.imag();
return batch<T, N>(sinh(x) * cos(y), cosh(x) * sin(y));
}
template <class T, std::size_t N>
struct sinh_kernel<batch<std::complex<T>, N>>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return sinh_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct sinh_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return sinh_complex_impl(z);
}
};
#endif
/********
* cosh *
********/
template <class T, std::size_t N>
inline batch<T, N> cosh_complex_impl(const batch<T, N>& z)
{
auto x = z.real();
auto y = z.imag();
return batch<T, N>(cosh(x) * cos(y), sinh(x) * sin(y));
}
template <class T, std::size_t N>
struct cosh_kernel<batch<std::complex<T>, N >>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return cosh_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct cosh_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return cosh_complex_impl(z);
}
};
#endif
/********
* tanh *
********/
template <class T, std::size_t N>
inline batch<T, N> tanh_complex_impl(const batch<T, N>& z)
{
using rvt = typename batch<T, N>::real_value_type;
using real_batch = typename batch<T, N>::real_batch;
auto x = z.real();
auto y = z.imag();
real_batch two = real_batch(rvt(2));
auto d = cosh(two * x) + cos(two * y);
return batch<T, N>(sinh(two * x) / d, sin(two * y) / d);
}
template <class T, std::size_t N>
struct tanh_kernel<batch<std::complex<T>, N >>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return tanh_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct tanh_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return tanh_complex_impl(z);
}
};
#endif
/*********
* asinh *
*********/
template <class T, std::size_t N>
inline batch<T, N> asinh_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
b_type w = asin(b_type(-z.imag(), z.real()));
w = b_type(w.imag(), -w.real());
return w;
}
template <class T, std::size_t N>
struct asinh_kernel<batch<std::complex<T>, N >>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return asinh_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct asinh_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return asinh_complex_impl(z);
}
};
#endif
/*********
* acosh *
*********/
template <class T, std::size_t N>
inline batch<T, N> acosh_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
b_type w = acos(z);
w = b_type(-w.imag(), w.real());
return w;
}
template <class T, std::size_t N>
struct acosh_kernel<batch<std::complex<T>, N >>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return acosh_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct acosh_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return acosh_complex_impl(z);
}
};
#endif
/*********
* atanh *
*********/
template <class T, std::size_t N>
inline batch<T, N> atanh_complex_impl(const batch<T, N>& z)
{
using b_type = batch<T, N>;
b_type w = atan(b_type(-z.imag(), z.real()));
w = b_type(w.imag(), -w.real());
return w;
}
template <class T, std::size_t N>
struct atanh_kernel<batch<std::complex<T>, N >>
{
using batch_type = batch<std::complex<T>, N>;
static inline batch_type compute(const batch_type& z)
{
return atanh_complex_impl(z);
}
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct atanh_kernel<batch<xtl::xcomplex<T, T, i3ec>, N>>
{
using batch_type = batch<xtl::xcomplex<T, T, i3ec>, N>;
static inline batch_type compute(const batch_type& z)
{
return atanh_complex_impl(z);
}
};
#endif
}
namespace detail
{
template <class T>
T csqrt_scale_factor() noexcept;
template <class T>
T csqrt_scale() noexcept;
template <>
inline float csqrt_scale_factor<float>() noexcept
{
return 6.7108864e7f;
}
template <>
inline float csqrt_scale<float>() noexcept
{
return 1.220703125e-4f;
}
template <>
inline double csqrt_scale_factor<double>() noexcept
{
return 1.8014398509481984e16;
}
template <>
inline double csqrt_scale<double>() noexcept
{
return 7.450580596923828125e-9;
}
}
namespace detail
{
template <class T, std::size_t N>
struct complex_batch_kernel
{
using batch_type = batch<T, N>;
using batch_bool_type = typename simd_batch_traits<batch_type>::batch_bool_type;
using real_batch = typename batch_type::real_batch;
static real_batch abs(const batch_type& z)
{
return hypot(z.real(), z.imag());
}
static batch_type fma(const batch_type& a, const batch_type& b, const batch_type& c)
{
real_batch res_r = ::xsimd::fms(a.real(), b.real(), ::xsimd::fms(a.imag(), b.imag(), c.real()));
real_batch res_i = ::xsimd::fma(a.real(), b.imag(), ::xsimd::fma(a.imag(), b.real(), c.imag()));
return {res_r, res_i};
}
static batch_type fms(const batch_type& a, const batch_type& b, const batch_type& c)
{
real_batch res_r = ::xsimd::fms(a.real(), b.real(), ::xsimd::fma(a.imag(), b.imag(), c.real()));
real_batch res_i = ::xsimd::fma(a.real(), b.imag(), ::xsimd::fms(a.imag(), b.real(), c.imag()));
return {res_r, res_i};
}
static batch_type fnma(const batch_type& a, const batch_type& b, const batch_type& c)
{
real_batch res_r = - ::xsimd::fms(a.real(), b.real(), ::xsimd::fma(a.imag(), b.imag(), c.real()));
real_batch res_i = - ::xsimd::fma(a.real(), b.imag(), ::xsimd::fms(a.imag(), b.real(), c.imag()));
return {res_r, res_i};
}
static batch_type fnms(const batch_type& a, const batch_type& b, const batch_type& c)
{
real_batch res_r = - ::xsimd::fms(a.real(), b.real(), ::xsimd::fms(a.imag(), b.imag(), c.real()));
real_batch res_i = - ::xsimd::fma(a.real(), b.imag(), ::xsimd::fma(a.imag(), b.real(), c.imag()));
return {res_r, res_i};
}
static batch_type sqrt(const batch_type& z)
{
using rvt = typename real_batch::value_type;
real_batch x = z.real();
real_batch y = z.imag();
real_batch sqrt_x = xsimd::sqrt(fabs(x));
real_batch sqrt_hy = xsimd::sqrt(0.5 * fabs(y));
auto cond = (fabs(x) > real_batch(4.) || fabs(y) > real_batch(4.));
x = select(cond, x * 0.25, x * detail::csqrt_scale_factor<rvt>());
y = select(cond, y * 0.25, y * detail::csqrt_scale_factor<rvt>());
real_batch scale = select(cond, real_batch(2.), real_batch(detail::csqrt_scale<rvt>()));
real_batch r = abs(batch_type(x, y));
auto condxp = x > real_batch(0.);
real_batch t0 = select(condxp, xsimd::sqrt(0.5 * (r + x)), xsimd::sqrt(0.5 * (r - x)));
real_batch r0 = scale * fabs((0.5 * y) / t0);
t0 *= scale;
real_batch t = select(condxp, t0, r0);
r = select(condxp, r0, t0);
batch_type resg = select(y < real_batch(0.), batch_type(t, -r), batch_type(t, r));
real_batch ze(0.);
return select(y == ze,
select(x == ze,
batch_type(ze, ze),
select(x < ze, batch_type(ze, sqrt_x), batch_type(sqrt_x, ze))),
select(x == ze,
select(y > ze, batch_type(sqrt_hy, sqrt_hy), batch_type(sqrt_hy, -sqrt_hy)),
resg));
}
static batch_bool_type isnan(const batch_type& z)
{
return batch_bool_type(xsimd::isnan(z.real()) || xsimd::isnan(z.imag()));
}
};
template <class T, std::size_t N>
struct batch_kernel<std::complex<T>, N>
: public complex_batch_kernel<std::complex<T>, N>
{
};
#ifdef XSIMD_ENABLE_XTL_COMPLEX
template <class T, bool i3ec, std::size_t N>
struct batch_kernel<xtl::xcomplex<T, T, i3ec>, N>
: public complex_batch_kernel<xtl::xcomplex<T, T, i3ec>, N>
{
};
#endif
}
namespace detail
{
template <class B, bool is_complex>
struct real_imag_kernel
{
using return_type = typename B::real_batch;
static return_type real(const B& z)
{
return z.real();
}
static return_type imag(const B& z)
{
return z.imag();
}
};
template <class B>
struct real_imag_kernel<B, false>
{
using return_type = B;
static return_type real(const B& z)
{
return z;
}
static return_type imag(const B&)
{
return B(typename B::value_type(0));
}
};
}
template <class X>
inline real_batch_type_t<X> real(const simd_base<X>& z)
{
using batch_type = batch_type_t<X>;
constexpr bool is_cplx = detail::is_complex<typename batch_type::value_type>::value;
return detail::real_imag_kernel<batch_type, is_cplx>::real(z());
}
template <class X>
inline real_batch_type_t<X> imag(const simd_base<X>& z)
{
using batch_type = batch_type_t<X>;
constexpr bool is_cplx = detail::is_complex<typename batch_type::value_type>::value;
return detail::real_imag_kernel<batch_type, is_cplx>::imag(z());
}
template <class X>
inline real_batch_type_t<X> arg(const simd_base<X>& z)
{
return atan2(imag(z), real(z));
}
template <class X>
inline batch_type_t<X> conj(const simd_base<X>& z)
{
return X(z().real(), -z().imag());
}
template <class X>
inline real_batch_type_t<X> norm(const simd_base<X>& rhs)
{
return real(rhs) * real(rhs) + imag(rhs) * imag(rhs);
}
template <class X>
inline batch_type_t<X> proj(const simd_base<X>& rhs)
{
using batch_type = batch_type_t<X>;
using real_batch = typename simd_batch_traits<X>::real_batch;
auto cond = xsimd::isinf(rhs().real()) || xsimd::isinf(rhs().imag());
return select(cond, batch_type(infinity<real_batch>(), copysign(real_batch(0.), rhs().imag())), rhs());
}
}
#endif