1 /*************************************************************************** 2 * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and * 3 * Martin Renou * 4 * Copyright (c) QuantStack * 5 * * 6 * Distributed under the terms of the BSD 3-Clause License. * 7 * * 8 * The full license is in the file LICENSE, distributed with this software. * 9 ****************************************************************************/ 10 11 #ifndef XSIMD_COMPLEX_BASE_HPP 12 #define XSIMD_COMPLEX_BASE_HPP 13 14 #include <complex> 15 #include <cstddef> 16 #include <limits> 17 #include <ostream> 18 #include <cassert> 19 20 #ifdef XSIMD_ENABLE_XTL_COMPLEX 21 #include "xtl/xcomplex.hpp" 22 #endif 23 24 #include "xsimd_base.hpp" 25 #include "xsimd_utils.hpp" 26 27 namespace xsimd 28 { 29 /***************************** 30 * complex_batch_bool_traits * 31 *****************************/ 32 33 template <class C, class R, std::size_t N, std::size_t Align> 34 struct complex_batch_bool_traits 35 { 36 using value_type = C; 37 static constexpr std::size_t size = N; 38 using batch_type = batch<C, N>; 39 static constexpr std::size_t align = Align; 40 using real_batch = batch_bool<R, N>; 41 }; 42 43 /*************************** 44 * simd_complex_batch_bool * 45 ***************************/ 46 47 /** 48 * @class simd_complex_batch_bool 49 * @brief Base class for complex batch of boolean values. 50 * 51 * The simd_complex_batch_bool class is the base class for all classes representing 52 * a complex batch of boolean values. Complex batch of boolean values is meant for operations 53 * that may involve batches of complex numbers. Thus, the boolean values are stored as floating 54 * point values, and each type of batch of complex has its dedicated type of boolean batch. 55 * 56 * @tparam X The derived type 57 * @sa simd_complex_batch 58 */ 59 template <class X> 60 class simd_complex_batch_bool : public simd_batch_bool<X> 61 { 62 public: 63 64 using value_type = typename simd_batch_traits<X>::value_type; 65 static constexpr std::size_t size = simd_batch_traits<X>::size; 66 using real_batch = typename simd_batch_traits<X>::real_batch; 67 68 simd_complex_batch_bool() = default; 69 simd_complex_batch_bool(bool b); 70 simd_complex_batch_bool(const real_batch& b); 71 72 const real_batch& value() const; 73 74 bool operator[](std::size_t index) const; 75 76 private: 77 78 real_batch m_value; 79 }; 80 81 /************************ 82 * complex_batch_traits * 83 ************************/ 84 85 template <class C, class R, std::size_t N, std::size_t Align> 86 struct complex_batch_traits 87 { 88 using value_type = C; 89 static constexpr std::size_t size = N; 90 using batch_bool_type = batch_bool<C, N>; 91 static constexpr std::size_t align = Align; 92 using real_batch = batch<R, N>; 93 }; 94 95 /********************** 96 * simd_complex_batch * 97 **********************/ 98 99 template <class T> 100 struct is_ieee_compliant; 101 102 template <class T> 103 struct is_ieee_compliant<std::complex<T>> 104 : std::integral_constant<bool, std::numeric_limits<std::complex<T>>::is_iec559> 105 { 106 }; 107 108 #ifdef XSIMD_ENABLE_XTL_COMPLEX 109 template <class T> 110 struct is_ieee_compliant<xtl::xcomplex<T, T, false>> : std::false_type 111 { 112 }; 113 #endif 114 115 /** 116 * @class simd_complex_batch 117 * @brief Base class for batch complex numbers. 118 * 119 * The simd_complex_batch class is the base class for all classes representing 120 * a batch of complex numbers. Each type of batch (i.e. a class inheriting from 121 * simd_complex_batch) has its dedicated type of boolean batch (i.e. a class 122 * inheriting from simd_complex_batch_bool) for logical operations. 123 * 124 * Internally, a batch of complex numbers holds two batches of real numbers, one 125 * for the real part and one for the imaginary part. 126 * 127 * @tparam X The derived type 128 * @sa simd_complex_batch_bool 129 */ 130 template <class X> 131 class simd_complex_batch : public simd_base<X> 132 { 133 public: 134 135 using base_type = simd_base<X>; 136 using batch_reference = typename base_type::batch_reference; 137 using const_batch_reference = typename base_type::const_batch_reference; 138 using batch_type = X; 139 using value_type = typename simd_batch_traits<X>::value_type; 140 static constexpr std::size_t size = simd_batch_traits<X>::size; 141 using real_batch = typename simd_batch_traits<X>::real_batch; 142 using real_value_type = typename value_type::value_type; 143 144 simd_complex_batch() = default; 145 explicit simd_complex_batch(const value_type& v); 146 explicit simd_complex_batch(const real_value_type& v); 147 explicit simd_complex_batch(const real_batch& re); simd_complex_batch(const real_value_type * v)148 explicit simd_complex_batch(const real_value_type* v) : simd_complex_batch(real_batch(v)) {} 149 simd_complex_batch(const real_batch& re, const real_batch& im); simd_complex_batch(const real_value_type * re,const real_value_type * im)150 simd_complex_batch(const real_value_type* re, const real_value_type* im) : simd_complex_batch(real_batch(re), real_batch(im)) {} 151 152 real_batch& real(); 153 real_batch& imag(); 154 155 const real_batch& real() const; 156 const real_batch& imag() const; 157 158 X& operator+=(const X& rhs); 159 X& operator+=(const value_type& rhs); 160 X& operator+=(const real_batch& rhs); 161 X& operator+=(const real_value_type& rhs); 162 163 X& operator-=(const X& rhs); 164 X& operator-=(const value_type& rhs); 165 X& operator-=(const real_batch& rhs); 166 X& operator-=(const real_value_type& rhs); 167 168 X& operator*=(const X& rhs); 169 X& operator*=(const value_type& rhs); 170 X& operator*=(const real_batch& rhs); 171 X& operator*=(const real_value_type& rhs); 172 173 X& operator/=(const X& rhs); 174 X& operator/=(const value_type& rhs); 175 X& operator/=(const real_batch& rhs); 176 X& operator/=(const real_value_type& rhs); 177 178 template <class T> 179 X& load_aligned(const T* real_src, const T* imag_src); 180 template <class T> 181 X& load_unaligned(const T* real_src, const T* imag_src); 182 183 template <class T> 184 void store_aligned(T* real_dst, T* imag_dst) const; 185 template <class T> 186 void store_unaligned(T* real_dst, T* imag_dst) const; 187 188 template <class T> 189 typename std::enable_if<detail::is_complex<T>::value, X&>::type 190 load_aligned(const T* src); 191 template <class T> 192 typename std::enable_if<detail::is_complex<T>::value, X&>::type 193 load_unaligned(const T* src); 194 195 template <class T> 196 typename std::enable_if<!detail::is_complex<T>::value, X&>::type 197 load_aligned(const T* src); 198 template <class T> 199 typename std::enable_if<!detail::is_complex<T>::value, X&>::type 200 load_unaligned(const T* src); 201 202 template <class T> 203 inline typename std::enable_if<detail::is_complex<T>::value, void>::type 204 store_aligned(T* dst) const; 205 template <class T> 206 inline typename std::enable_if<detail::is_complex<T>::value, void>::type 207 store_unaligned(T* dst) const; 208 209 template <class T> 210 inline typename std::enable_if<!detail::is_complex<T>::value, void>::type 211 store_aligned(T* dst) const; 212 template <class T> 213 inline typename std::enable_if<!detail::is_complex<T>::value, void>::type 214 store_unaligned(T* dst) const; 215 216 value_type operator[](std::size_t index) const; 217 218 batch_reference get(); 219 const_batch_reference get() const; 220 221 protected: 222 223 real_batch m_real; 224 real_batch m_imag; 225 }; 226 227 template <class X> 228 X operator+(const simd_complex_batch<X>& rhs); 229 230 template <class X> 231 X operator-(const simd_complex_batch<X>& rhs); 232 233 template <class X> 234 X operator+(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs); 235 template <class X> 236 X operator+(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs); 237 template <class X> 238 X operator+(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs); 239 template <class X> 240 X operator+(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs); 241 template <class X> 242 X operator+(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs); 243 template <class X> 244 X operator+(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs); 245 template <class X> 246 X operator+(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs); 247 248 template <class X> 249 X operator-(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs); 250 template <class X> 251 X operator-(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs); 252 template <class X> 253 X operator-(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs); 254 template <class X> 255 X operator-(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs); 256 template <class X> 257 X operator-(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs); 258 template <class X> 259 X operator-(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs); 260 template <class X> 261 X operator-(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs); 262 263 template <class X> 264 X operator*(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs); 265 template <class X> 266 X operator*(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs); 267 template <class X> 268 X operator*(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs); 269 template <class X> 270 X operator*(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs); 271 template <class X> 272 X operator*(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs); 273 template <class X> 274 X operator*(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs); 275 template <class X> 276 X operator*(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs); 277 278 template <class X> 279 X operator/(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs); 280 template <class X> 281 X operator/(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs); 282 template <class X> 283 X operator/(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs); 284 template <class X> 285 X operator/(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs); 286 template <class X> 287 X operator/(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs); 288 template <class X> 289 X operator/(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs); 290 template <class X> 291 X operator/(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs); 292 293 template <class X> 294 typename simd_batch_traits<X>::value_type 295 hadd(const simd_complex_batch<X>& rhs); 296 297 template <class X> 298 X select(const typename simd_batch_traits<X>::batch_bool_type& cond, 299 const simd_complex_batch<X>& a, 300 const simd_complex_batch<X>& b); 301 302 template <class X> 303 typename simd_batch_traits<X>::batch_bool_type 304 operator==(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs); 305 306 template <class X> 307 typename simd_batch_traits<X>::batch_bool_type 308 operator!=(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs); 309 310 template <class X> 311 std::ostream& operator<<(std::ostream& out, const simd_complex_batch<X>& rhs); 312 313 /******************************************* 314 * xsimd_complex_batch_bool implementation * 315 *******************************************/ 316 317 /** 318 * Initializes all the values of the batch to \c b 319 */ 320 template <class X> simd_complex_batch_bool(bool b)321 inline simd_complex_batch_bool<X>::simd_complex_batch_bool(bool b) 322 : m_value(b) 323 { 324 } 325 326 /** 327 * Initializes the values of the batch with those of the real batch \c b. 328 * A real batch contains scalars whose type is the \c value_type of 329 * the complex number type. 330 */ 331 template <class X> simd_complex_batch_bool(const real_batch & b)332 inline simd_complex_batch_bool<X>::simd_complex_batch_bool(const real_batch& b) 333 : m_value(b) 334 { 335 } 336 337 template <class X> value() const338 inline auto simd_complex_batch_bool<X>::value() const -> const real_batch& 339 { 340 return m_value; 341 } 342 343 template <class X> operator [](std::size_t index) const344 inline bool simd_complex_batch_bool<X>::operator[](std::size_t index) const 345 { 346 return m_value[index]; 347 } 348 349 namespace detail 350 { 351 template <class T, std::size_t N> 352 struct batch_bool_complex_kernel 353 { 354 using batch_type = batch_bool<T, N>; 355 bitwise_andxsimd::detail::batch_bool_complex_kernel356 static batch_type bitwise_and(const batch_type& lhs, const batch_type& rhs) 357 { 358 return lhs.value() & rhs.value(); 359 } 360 bitwise_orxsimd::detail::batch_bool_complex_kernel361 static batch_type bitwise_or(const batch_type& lhs, const batch_type& rhs) 362 { 363 return lhs.value() | rhs.value(); 364 } 365 bitwise_xorxsimd::detail::batch_bool_complex_kernel366 static batch_type bitwise_xor(const batch_type& lhs, const batch_type& rhs) 367 { 368 return lhs.value() ^ rhs.value(); 369 } 370 bitwise_notxsimd::detail::batch_bool_complex_kernel371 static batch_type bitwise_not(const batch_type& rhs) 372 { 373 return ~(rhs.value()); 374 } 375 bitwise_andnotxsimd::detail::batch_bool_complex_kernel376 static batch_type bitwise_andnot(const batch_type& lhs, const batch_type& rhs) 377 { 378 return xsimd::bitwise_andnot(lhs.value(), rhs.value()); 379 } 380 equalxsimd::detail::batch_bool_complex_kernel381 static batch_type equal(const batch_type& lhs, const batch_type& rhs) 382 { 383 return lhs.value() == rhs.value(); 384 } 385 not_equalxsimd::detail::batch_bool_complex_kernel386 static batch_type not_equal(const batch_type& lhs, const batch_type& rhs) 387 { 388 return lhs.value() != rhs.value(); 389 } 390 allxsimd::detail::batch_bool_complex_kernel391 static bool all(const batch_type& rhs) 392 { 393 return xsimd::all(rhs.value()); 394 } 395 anyxsimd::detail::batch_bool_complex_kernel396 static bool any(const batch_type& rhs) 397 { 398 return xsimd::any(rhs.value()); 399 } 400 }; 401 402 template <class T, std::size_t N> 403 struct batch_bool_kernel<std::complex<T>, N> 404 : batch_bool_complex_kernel<std::complex<T>, N> 405 { 406 }; 407 408 #ifdef XSIMD_ENABLE_XTL_COMPLEX 409 template <class T, std::size_t N, bool ieee_compliant> 410 struct batch_bool_kernel<xtl::xcomplex<T, T, ieee_compliant>, N> 411 : batch_bool_complex_kernel<xtl::xcomplex<T, T, ieee_compliant>, N> 412 { 413 }; 414 #endif 415 } 416 417 /************************************** 418 * xsimd_complex_batch implementation * 419 **************************************/ 420 421 /** 422 * Initializes all the values of the batch to the complex value \c v. 423 */ 424 template <class X> simd_complex_batch(const value_type & v)425 inline simd_complex_batch<X>::simd_complex_batch(const value_type& v) 426 : m_real(v.real()), m_imag(v.imag()) 427 { 428 } 429 430 /** 431 * Initializes all the values of the batch to the real value \c v. 432 */ 433 template <class X> simd_complex_batch(const real_value_type & v)434 inline simd_complex_batch<X>::simd_complex_batch(const real_value_type& v) 435 : m_real(v), m_imag(real_value_type(0)) 436 { 437 } 438 439 /** 440 * Initializes the values of the batch whith those of the real batch \c re. 441 * Imaginary parts are set to 0. 442 */ 443 template <class X> simd_complex_batch(const real_batch & re)444 inline simd_complex_batch<X>::simd_complex_batch(const real_batch& re) 445 : m_real(re), m_imag(real_value_type(0)) 446 { 447 } 448 449 /** 450 * Initializes the batch with two real batch, one for the real part and one for the inamginary 451 * part. 452 */ 453 template <class X> simd_complex_batch(const real_batch & re,const real_batch & im)454 inline simd_complex_batch<X>::simd_complex_batch(const real_batch& re, const real_batch& im) 455 : m_real(re), m_imag(im) 456 { 457 } 458 459 /** 460 * Returns a batch for the real part. 461 */ 462 template <class X> real()463 inline auto simd_complex_batch<X>::real() -> real_batch& 464 { 465 return m_real; 466 } 467 468 /** 469 * Returns a batch for the imaginary part. 470 */ 471 template <class X> imag()472 inline auto simd_complex_batch<X>::imag() -> real_batch& 473 { 474 return m_imag; 475 } 476 477 /** 478 * Returns a const batch for the real part 479 */ 480 template <class X> real() const481 inline auto simd_complex_batch<X>::real() const -> const real_batch& 482 { 483 return m_real; 484 } 485 486 /** 487 * Returns a const batch for the imaginary part. 488 */ 489 template <class X> imag() const490 inline auto simd_complex_batch<X>::imag() const -> const real_batch& 491 { 492 return m_imag; 493 } 494 495 /** 496 * @name Arithmetic computed assignment 497 */ 498 //@{ 499 /** 500 * Adds the batch \c rhs to \c this. 501 * @param rhs the batch to add. 502 * @return a reference to \c this. 503 */ 504 template <class X> operator +=(const X & rhs)505 inline X& simd_complex_batch<X>::operator+=(const X& rhs) 506 { 507 m_real += rhs.real(); 508 m_imag += rhs.imag(); 509 return (*this)(); 510 } 511 512 /** 513 * Adds the scalar \c rhs to each value contained in \c this. 514 * @param rhs the scalar to add. 515 * @return a reference to \c this. 516 */ 517 template <class X> operator +=(const value_type & rhs)518 inline X& simd_complex_batch<X>::operator+=(const value_type& rhs) 519 { 520 return (*this)() += X(rhs); 521 } 522 523 /** 524 * Adds the real batch \c rhs to \c this. 525 * @param rhs the real batch to add. 526 * @return a reference to \c this. 527 */ 528 template <class X> operator +=(const real_batch & rhs)529 inline X& simd_complex_batch<X>::operator+=(const real_batch& rhs) 530 { 531 m_real += rhs; 532 return (*this)(); 533 } 534 535 /** 536 * Adds the real scalar \c rhs to each value contained in \c this. 537 * @param rhs the real scalar to add. 538 * @return a reference to \c this. 539 */ 540 template <class X> operator +=(const real_value_type & rhs)541 inline X& simd_complex_batch<X>::operator+=(const real_value_type& rhs) 542 { 543 return (*this)() += real_batch(rhs); 544 } 545 546 /** 547 * Substracts the batch \c rhs to \c this. 548 * @param rhs the batch to substract. 549 * @return a reference to \c this. 550 */ 551 template <class X> operator -=(const X & rhs)552 inline X& simd_complex_batch<X>::operator-=(const X& rhs) 553 { 554 m_real -= rhs.real(); 555 m_imag -= rhs.imag(); 556 return (*this)(); 557 } 558 559 /** 560 * Substracts the scalar \c rhs to each value contained in \c this. 561 * @param rhs the scalar to substract. 562 * @return a reference to \c this. 563 */ 564 template <class X> operator -=(const value_type & rhs)565 inline X& simd_complex_batch<X>::operator-=(const value_type& rhs) 566 { 567 return (*this)() -= X(rhs); 568 } 569 570 /** 571 * Substracts the real batch \c rhs to \c this. 572 * @param rhs the batch to substract. 573 * @return a reference to \c this. 574 */ 575 template <class X> operator -=(const real_batch & rhs)576 inline X& simd_complex_batch<X>::operator-=(const real_batch& rhs) 577 { 578 m_real -= rhs; 579 return (*this)(); 580 } 581 582 /** 583 * Substracts the real scalar \c rhs to each value contained in \c this. 584 * @param rhs the real scalar to substract. 585 * @return a reference to \c this. 586 */ 587 template <class X> operator -=(const real_value_type & rhs)588 inline X& simd_complex_batch<X>::operator-=(const real_value_type& rhs) 589 { 590 return (*this)() -= real_batch(rhs); 591 } 592 593 namespace detail 594 { 595 template <class X, bool ieee_compliant> 596 struct complex_batch_multiplier 597 { 598 using real_batch = typename simd_batch_traits<X>::real_batch; 599 mulxsimd::detail::complex_batch_multiplier600 inline static X mul(const X& lhs, const X& rhs) 601 { 602 real_batch a = lhs.real(); 603 real_batch b = lhs.imag(); 604 real_batch c = rhs.real(); 605 real_batch d = rhs.imag(); 606 return X(a*c - b*d, a*d + b*c); 607 } 608 divxsimd::detail::complex_batch_multiplier609 inline static X div(const X& lhs, const X& rhs) 610 { 611 real_batch a = lhs.real(); 612 real_batch b = lhs.imag(); 613 real_batch c = rhs.real(); 614 real_batch d = rhs.imag(); 615 real_batch e = c*c + d*d; 616 return X((c*a + d*b) / e, (c*b - d*a) / e); 617 } 618 }; 619 } 620 621 /** 622 * Multiplies \c this with the batch \c rhs. 623 * @param rhs the batch involved in the multiplication. 624 * @return a reference to \c this. 625 */ 626 template <class X> operator *=(const X & rhs)627 inline X& simd_complex_batch<X>::operator*=(const X& rhs) 628 { 629 using kernel = detail::complex_batch_multiplier<X, is_ieee_compliant<value_type>::value>; 630 (*this)() = kernel::mul((*this)(), rhs); 631 return (*this)(); 632 } 633 634 /** 635 * Multiplies each scalar contained in \c this with the scalar \c rhs. 636 * @param rhs the scalar involved in the multiplication. 637 * @return a reference to \c this. 638 */ 639 template <class X> operator *=(const value_type & rhs)640 inline X& simd_complex_batch<X>::operator*=(const value_type& rhs) 641 { 642 return (*this)() *= X(rhs); 643 } 644 645 /** 646 * Multiplies \c this with the real batch \c rhs. 647 * @param rhs the real batch involved in the multiplication. 648 * @return a reference to \c this. 649 */ 650 template <class X> operator *=(const real_batch & rhs)651 inline X& simd_complex_batch<X>::operator*=(const real_batch& rhs) 652 { 653 m_real *= rhs; 654 m_imag *= rhs; 655 return (*this)(); 656 } 657 658 /** 659 * Multiplies each scalar contained in \c this with the real scalar \c rhs. 660 * @param rhs the real scalar involved in the multiplication. 661 * @return a reference to \c this. 662 */ 663 template <class X> operator *=(const real_value_type & rhs)664 inline X& simd_complex_batch<X>::operator*=(const real_value_type& rhs) 665 { 666 return (*this)() *= real_batch(rhs); 667 } 668 669 /** 670 * Divides \c this by the batch \c rhs. 671 * @param rhs the batch involved in the division. 672 * @return a reference to \c this. 673 */ 674 template <class X> operator /=(const X & rhs)675 inline X& simd_complex_batch<X>::operator/=(const X& rhs) 676 { 677 using kernel = detail::complex_batch_multiplier<X, is_ieee_compliant<value_type>::value>; 678 (*this)() = kernel::div((*this)(), rhs); 679 return (*this)(); 680 } 681 682 /** 683 * Divides each scalar contained in \c this by the scalar \c rhs. 684 * @param rhs the scalar involved in the division. 685 * @return a reference to \c this. 686 */ 687 template <class X> operator /=(const value_type & rhs)688 inline X& simd_complex_batch<X>::operator/=(const value_type& rhs) 689 { 690 return (*this)() /= X(rhs); 691 } 692 693 /** 694 * Divides \c this by the real batch \c rhs. 695 * @param rhs the real batch involved in the division. 696 * @return a reference to \c this. 697 */ 698 template <class X> operator /=(const real_batch & rhs)699 inline X& simd_complex_batch<X>::operator/=(const real_batch& rhs) 700 { 701 m_real /= rhs; 702 m_imag /= rhs; 703 return (*this)(); 704 } 705 706 /** 707 * Divides each scalar contained in \c this by the real scalar \c rhs. 708 * @param rhs the real scalar involved in the division. 709 * @return a reference to \c this. 710 */ 711 template <class X> operator /=(const real_value_type & rhs)712 inline X& simd_complex_batch<X>::operator/=(const real_value_type& rhs) 713 { 714 return (*this)() /= real_batch(rhs); 715 } 716 //@} 717 718 /** 719 * @name Load and store methods 720 */ 721 //@{ 722 /** 723 * Loads the N contiguous values pointed by \c real_src into the batch holding 724 * the real values, and N contiguous values pointed by \c imag_src into the 725 * batch holding the imaginary values. 726 * \c real_src and \c imag_src must be aligned. 727 */ 728 template <class X> 729 template <class T> load_aligned(const T * real_src,const T * imag_src)730 inline X& simd_complex_batch<X>::load_aligned(const T* real_src, const T* imag_src) 731 { 732 m_real.load_aligned(real_src); 733 m_imag.load_aligned(imag_src); 734 return (*this)(); 735 } 736 737 /** 738 * Loads the N contiguous values pointed by \c real_src into the batch holding 739 * the real values, and N contiguous values pointed by \c imag_src into the 740 * batch holding the imaginary values. 741 * \c real_src and \c imag_src are not required to be aligned. 742 */ 743 template <class X> 744 template <class T> load_unaligned(const T * real_src,const T * imag_src)745 inline X& simd_complex_batch<X>::load_unaligned(const T* real_src, const T* imag_src) 746 { 747 m_real.load_unaligned(real_src); 748 m_imag.load_unaligned(imag_src); 749 return (*this)(); 750 } 751 752 /** 753 * Stores the N values of the batch holding the real values into a contiguous array 754 * pointed by \c real_dst., and the N values of the batch holding the imaginary values 755 * into a contiguous array pointer by \c imag_dst. 756 * \c real_dst and \c imag_dst must be aligned. 757 */ 758 template <class X> 759 template <class T> store_aligned(T * real_dst,T * imag_dst) const760 inline void simd_complex_batch<X>::store_aligned(T* real_dst, T* imag_dst) const 761 { 762 m_real.store_aligned(real_dst); 763 m_imag.store_aligned(imag_dst); 764 } 765 766 /** 767 * Stores the N values of the batch holding the real values into a contiguous array 768 * pointed by \c real_dst., and the N values of the batch holding the imaginary values 769 * into a contiguous array pointer by \c imag_dst. 770 * \c real_dst and \c imag_dst are not required to be aligned. 771 */ 772 template <class X> 773 template <class T> store_unaligned(T * real_dst,T * imag_dst) const774 inline void simd_complex_batch<X>::store_unaligned(T* real_dst, T* imag_dst) const 775 { 776 m_real.store_unaligned(real_dst); 777 m_imag.store_unaligned(imag_dst); 778 } 779 780 /** 781 * Loads the N contiguous values pointed by \c src into the batch. 782 * \c src must be aligned. 783 */ 784 template <class X> 785 template <class T> 786 inline typename std::enable_if<detail::is_complex<T>::value, X&>::type load_aligned(const T * src)787 simd_complex_batch<X>::load_aligned(const T* src) 788 { 789 using tmp_value_type = typename T::value_type; 790 const tmp_value_type* rbuf = reinterpret_cast<const tmp_value_type*>(src); 791 real_batch hi, lo; 792 hi.load_aligned(rbuf); 793 lo.load_aligned(rbuf + size); 794 return (*this)().load_complex(hi, lo); 795 } 796 797 /** 798 * Loads the N contiguous values pointed by \c src into the batch. 799 * \c src is not required to be aligned. 800 */ 801 template <class X> 802 template <class T> 803 inline typename std::enable_if<detail::is_complex<T>::value, X&>::type load_unaligned(const T * src)804 simd_complex_batch<X>::load_unaligned(const T* src) 805 { 806 using tmp_value_type = typename T::value_type; 807 const tmp_value_type* rbuf = reinterpret_cast<const tmp_value_type*>(src); 808 real_batch hi, lo; 809 hi.load_unaligned(rbuf); 810 lo.load_unaligned(rbuf + size); 811 return (*this)().load_complex(hi, lo); 812 } 813 814 ///@cond DOXYGEN_INCLUDE_SFINAE 815 template <class X> 816 template <class T> 817 inline typename std::enable_if<!detail::is_complex<T>::value, X&>::type load_aligned(const T * src)818 simd_complex_batch<X>::load_aligned(const T* src) 819 { 820 m_real.load_aligned(src); 821 m_imag = real_batch(real_value_type(0)); 822 return (*this)(); 823 } 824 825 template <class X> 826 template <class T> 827 inline typename std::enable_if<!detail::is_complex<T>::value, X&>::type load_unaligned(const T * src)828 simd_complex_batch<X>::load_unaligned(const T* src) 829 { 830 m_real.load_unaligned(src); 831 m_imag = real_batch(real_value_type(0)); 832 return (*this)(); 833 } 834 /// @endcond 835 836 /** 837 * Stores the N values of the batch into a contiguous array of complex 838 * pointed by \c dst. \c dst must be aligned. 839 */ 840 template <class X> 841 template <class T> 842 inline typename std::enable_if<detail::is_complex<T>::value, void>::type store_aligned(T * dst) const843 simd_complex_batch<X>::store_aligned(T* dst) const 844 { 845 real_batch hi = (*this)().get_complex_high(); 846 real_batch lo = (*this)().get_complex_low(); 847 using tmp_value_type = typename T::value_type; 848 tmp_value_type* rbuf = reinterpret_cast<tmp_value_type*>(dst); 849 hi.store_aligned(rbuf); 850 lo.store_aligned(rbuf + size); 851 } 852 853 /** 854 * Stores the N values of the batch into a contiguous array of reals 855 * pointed by \c dst. \c dst must be aligned. 856 */ 857 template <class X> 858 template <class T> 859 inline typename std::enable_if<!detail::is_complex<T>::value, void>::type store_aligned(T * dst) const860 simd_complex_batch<X>::store_aligned(T* dst) const 861 { 862 m_real.store_aligned(dst); 863 assert(all(m_imag == 0) && "no imaginary part"); 864 } 865 866 /** 867 * Stores the N values of the batch into a contiguous array of complex 868 * pointed by \c dst. \c dst is not required to be aligned. 869 */ 870 template <class X> 871 template <class T> 872 inline typename std::enable_if<detail::is_complex<T>::value, void>::type store_unaligned(T * dst) const873 simd_complex_batch<X>::store_unaligned(T* dst) const 874 { 875 real_batch hi = (*this)().get_complex_high(); 876 real_batch lo = (*this)().get_complex_low(); 877 using tmp_value_type = typename T::value_type; 878 tmp_value_type* rbuf = reinterpret_cast<tmp_value_type*>(dst); 879 hi.store_unaligned(rbuf); 880 lo.store_unaligned(rbuf + size); 881 } 882 883 /** 884 * Stores the N values of the batch into a contiguous array of reals 885 * pointed by \c dst. \c dst is not required to be aligned. 886 */ 887 template <class X> 888 template <class T> 889 inline typename std::enable_if<!detail::is_complex<T>::value, void>::type store_unaligned(T * dst) const890 simd_complex_batch<X>::store_unaligned(T* dst) const 891 { 892 m_real.store_aligned(dst); 893 assert(all(m_imag == 0) && "no imaginary part"); 894 } 895 896 //@} 897 898 template <class X> operator [](std::size_t index) const899 inline auto simd_complex_batch<X>::operator[](std::size_t index) const -> value_type 900 { 901 return value_type(m_real[index], m_imag[index]); 902 } 903 904 template <class X> get()905 inline auto simd_complex_batch<X>::get() -> batch_reference 906 { 907 return this->derived_cast(); 908 } 909 910 template <class X> get() const911 inline auto simd_complex_batch<X>::get() const -> const_batch_reference 912 { 913 return this->derived_cast(); 914 } 915 916 /******************************** 917 * simd_complex_batch operators * 918 ********************************/ 919 920 /** 921 * @defgroup simd_complex_batch_arithmetic Arithmetic operators 922 */ 923 924 /** 925 * @ingroup simd_complex_batch_arithmetic 926 * 927 * No-op on \c rhs. 928 * @tparam X the actual type of batch. 929 * @param rhs batch involved in the operation. 930 * @return the opposite of \c rhs. 931 */ 932 template <class X> operator +(const simd_complex_batch<X> & rhs)933 inline X operator+(const simd_complex_batch<X>& rhs) 934 { 935 return rhs(); 936 } 937 938 /** 939 * @ingroup simd_complex_batch_arithmetic 940 * 941 * Computes the opposite of the batch \c rhs. 942 * @tparam X the actual type of batch. 943 * @param rhs batch involved in the operation. 944 * @return the opposite of \c rhs. 945 */ 946 template <class X> operator -(const simd_complex_batch<X> & rhs)947 inline X operator-(const simd_complex_batch<X>& rhs) 948 { 949 return X(-rhs().real(), -rhs().imag()); 950 } 951 952 /** 953 * @ingroup simd_complex_batch_arithmetic 954 * 955 * Computes the sum of the batches \c lhs and \c rhs. 956 * @tparam X the actual type of batch. 957 * @param lhs batch involved in the addition. 958 * @param rhs batch involved in the addition. 959 * @return the result of the addition. 960 */ 961 template <class X> operator +(const simd_complex_batch<X> & lhs,const simd_complex_batch<X> & rhs)962 inline X operator+(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs) 963 { 964 X tmp(lhs()); 965 return tmp += rhs(); 966 } 967 968 /** 969 * @ingroup simd_complex_batch_arithmetic 970 * 971 * Computes the sum of the batch \c lhs and the scalar \c rhs. Equivalent to the 972 * sum of two batches where all the values of the second one are initialized to 973 * \c rhs. 974 * @tparam X the actual type of batch. 975 * @param lhs batch involved in the addition. 976 * @param rhs scalar involved in the addition. 977 * @return the result of the addition. 978 */ 979 template <class X> operator +(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::value_type & rhs)980 inline X operator+(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs) 981 { 982 X tmp(lhs()); 983 return tmp += X(rhs); 984 } 985 986 /** 987 * @ingroup simd_complex_batch_arithmetic 988 * 989 * Computes the sum of the scalar \c lhs and the batch \c rhs. Equivalent to the 990 * sum of two batches where all the values of the first one are initialized to 991 * \c rhs. 992 * @tparam X the actual type of batch. 993 * @param lhs scalar involved in the addition. 994 * @param rhs batch involved in the addition. 995 * @return the result of the addition. 996 */ 997 template <class X> operator +(const typename simd_batch_traits<X>::value_type & lhs,const simd_complex_batch<X> & rhs)998 inline X operator+(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs) 999 { 1000 X tmp(lhs); 1001 return tmp += rhs(); 1002 } 1003 1004 /** 1005 * @ingroup simd_complex_batch_arithmetic 1006 * 1007 * Computes the sum of the batches \c lhs and \c rhs. 1008 * @tparam X the actual type of batch. 1009 * @param lhs batch involved in the addition. 1010 * @param rhs real batch involved in the addition. 1011 * @return the result of the addition. 1012 */ 1013 template <class X> operator +(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_batch & rhs)1014 inline X operator+(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs) 1015 { 1016 X tmp(lhs()); 1017 return tmp += X(rhs); 1018 } 1019 1020 /** 1021 * @ingroup simd_complex_batch_arithmetic 1022 * 1023 * Computes the sum of the batches \c lhs and \c rhs. 1024 * @tparam X the actual type of batch. 1025 * @param lhs real batch involved in the addition. 1026 * @param rhs batch involved in the addition. 1027 * @return the result of the addition. 1028 */ 1029 template <class X> operator +(const typename simd_batch_traits<X>::real_batch & lhs,const simd_complex_batch<X> & rhs)1030 inline X operator+(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs) 1031 { 1032 X tmp(lhs); 1033 return tmp += rhs(); 1034 } 1035 1036 /** 1037 * @ingroup simd_complex_batch_arithmetic 1038 * 1039 * Computes the sum of the batch \c lhs and the real scalar \c rhs. Equivalent to the 1040 * sum of two batches where all the values of the second one are initialized to 1041 * \c rhs. 1042 * @tparam X the actual type of batch. 1043 * @param lhs batch involved in the addition. 1044 * @param rhs real scalar involved in the addition. 1045 * @return the result of the addition. 1046 */ 1047 template <class X> operator +(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_value_type & rhs)1048 inline X operator+(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs) 1049 { 1050 X tmp(lhs()); 1051 return tmp += X(rhs); 1052 } 1053 1054 /** 1055 * @ingroup simd_complex_batch_arithmetic 1056 * 1057 * Computes the sum of the real scalar \c lhs and the batch \c rhs. Equivalent to the 1058 * sum of two batches where all the values of the first one are initialized to 1059 * \c rhs. 1060 * @tparam X the actual type of batch. 1061 * @param lhs real scalar involved in the addition. 1062 * @param rhs batch involved in the addition. 1063 * @return the result of the addition. 1064 */ 1065 template <class X> operator +(const typename simd_batch_traits<X>::real_value_type & lhs,const simd_complex_batch<X> & rhs)1066 inline X operator+(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs) 1067 { 1068 X tmp(lhs); 1069 return tmp += rhs(); 1070 } 1071 1072 /** 1073 * @ingroup simd_complex_batch_arithmetic 1074 * 1075 * Computes the difference of the batches \c lhs and \c rhs. 1076 * @tparam X the actual type of batch. 1077 * @param lhs batch involved in the difference. 1078 * @param rhs batch involved in the difference. 1079 * @return the result of the difference. 1080 */ 1081 template <class X> operator -(const simd_complex_batch<X> & lhs,const simd_complex_batch<X> & rhs)1082 inline X operator-(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs) 1083 { 1084 X tmp(lhs()); 1085 return tmp -= rhs(); 1086 } 1087 1088 /** 1089 * @ingroup simd_complex_batch_arithmetic 1090 * 1091 * Computes the difference of the batch \c lhs and the scalar \c rhs. Equivalent to the 1092 * difference of two batches where all the values of the second one are initialized to 1093 * \c rhs. 1094 * @tparam X the actual type of batch. 1095 * @param lhs batch involved in the difference. 1096 * @param rhs scalar involved in the difference. 1097 * @return the result of the difference. 1098 */ 1099 template <class X> operator -(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::value_type & rhs)1100 inline X operator-(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs) 1101 { 1102 X tmp(lhs()); 1103 return tmp -= X(rhs); 1104 } 1105 1106 /** 1107 * @ingroup simd_complex_batch_arithmetic 1108 * 1109 * Computes the difference of the scalar \c lhs and the batch \c rhs. Equivalent to the 1110 * difference of two batches where all the values of the first one are initialized to 1111 * \c rhs. 1112 * @tparam X the actual type of batch. 1113 * @param lhs scalar involved in the difference. 1114 * @param rhs batch involved in the difference. 1115 * @return the result of the difference. 1116 */ 1117 template <class X> operator -(const typename simd_batch_traits<X>::value_type & lhs,const simd_complex_batch<X> & rhs)1118 inline X operator-(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs) 1119 { 1120 X tmp(lhs); 1121 return tmp -= rhs(); 1122 } 1123 1124 /** 1125 * @ingroup simd_complex_batch_arithmetic 1126 * 1127 * Computes the difference of the batches \c lhs and \c rhs. 1128 * @tparam X the actual type of batch. 1129 * @param lhs batch involved in the difference. 1130 * @param rhs real batch involved in the difference. 1131 * @return the result of the difference. 1132 */ 1133 template <class X> operator -(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_batch & rhs)1134 inline X operator-(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs) 1135 { 1136 X tmp(lhs()); 1137 return tmp -= X(rhs); 1138 } 1139 1140 /** 1141 * @ingroup simd_complex_batch_arithmetic 1142 * 1143 * Computes the difference of the batches \c lhs and \c rhs. 1144 * @tparam X the actual type of batch. 1145 * @param lhs real batch involved in the difference. 1146 * @param rhs batch involved in the difference. 1147 * @return the result of the difference. 1148 */ 1149 template <class X> operator -(const typename simd_batch_traits<X>::real_batch & lhs,const simd_complex_batch<X> & rhs)1150 inline X operator-(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs) 1151 { 1152 X tmp(lhs); 1153 return tmp -= rhs(); 1154 } 1155 1156 /** 1157 * @ingroup simd_complex_batch_arithmetic 1158 * 1159 * Computes the difference of the batch \c lhs and the real scalar \c rhs. Equivalent to the 1160 * difference of two batches where all the values of the second one are initialized to 1161 * \c rhs. 1162 * @tparam X the actual type of batch. 1163 * @param lhs batch involved in the difference. 1164 * @param rhs real scalar involved in the difference. 1165 * @return the result of the difference. 1166 */ 1167 template <class X> operator -(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_value_type & rhs)1168 inline X operator-(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs) 1169 { 1170 X tmp(lhs()); 1171 return tmp -= X(rhs); 1172 } 1173 1174 /** 1175 * @ingroup simd_complex_batch_arithmetic 1176 * 1177 * Computes the difference of the real scalar \c lhs and the batch \c rhs. Equivalent to the 1178 * difference of two batches where all the values of the first one are initialized to 1179 * \c rhs. 1180 * @tparam X the actual type of batch. 1181 * @param lhs real scalar involved in the difference. 1182 * @param rhs batch involved in the difference. 1183 * @return the result of the difference. 1184 */ 1185 template <class X> operator -(const typename simd_batch_traits<X>::real_value_type & lhs,const simd_complex_batch<X> & rhs)1186 inline X operator-(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs) 1187 { 1188 X tmp(lhs); 1189 return tmp -= rhs(); 1190 } 1191 1192 /** 1193 * @ingroup simd_complex_batch_arithmetic 1194 * 1195 * Computes the product of the batches \c lhs and \c rhs. 1196 * @tparam X the actual type of batch. 1197 * @param lhs batch involved in the product. 1198 * @param rhs batch involved in the product. 1199 * @return the result of the product. 1200 */ 1201 template <class X> operator *(const simd_complex_batch<X> & lhs,const simd_complex_batch<X> & rhs)1202 inline X operator*(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs) 1203 { 1204 X tmp(lhs()); 1205 return tmp *= rhs(); 1206 } 1207 1208 /** 1209 * @ingroup simd_complex_batch_arithmetic 1210 * 1211 * Computes the product of the batch \c lhs and the scalar \c rhs. Equivalent to the 1212 * product of two batches where all the values of the second one are initialized to 1213 * \c rhs. 1214 * @tparam X the actual type of batch. 1215 * @param lhs batch involved in the product. 1216 * @param rhs scalar involved in the product. 1217 * @return the result of the product. 1218 */ 1219 template <class X> operator *(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::value_type & rhs)1220 inline X operator*(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs) 1221 { 1222 X tmp(lhs()); 1223 return tmp *= X(rhs); 1224 } 1225 1226 /** 1227 * @ingroup simd_complex_batch_arithmetic 1228 * 1229 * Computes the product of the scalar \c lhs and the batch \c rhs. Equivalent to the 1230 * difference of two batches where all the values of the first one are initialized to 1231 * \c rhs. 1232 * @tparam X the actual type of batch. 1233 * @param lhs scalar involved in the product. 1234 * @param rhs batch involved in the product. 1235 * @return the result of the product. 1236 */ 1237 template <class X> operator *(const typename simd_batch_traits<X>::value_type & lhs,const simd_complex_batch<X> & rhs)1238 inline X operator*(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs) 1239 { 1240 X tmp(lhs); 1241 return tmp *= rhs(); 1242 } 1243 1244 /** 1245 * @ingroup simd_complex_batch_arithmetic 1246 * 1247 * Computes the product of the batches \c lhs and \c rhs. 1248 * @tparam X the actual type of batch. 1249 * @param lhs batch involved in the product. 1250 * @param rhs real batch involved in the product. 1251 * @return the result of the product. 1252 */ 1253 template <class X> operator *(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_batch & rhs)1254 inline X operator*(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs) 1255 { 1256 X tmp(lhs()); 1257 return tmp *= X(rhs); 1258 } 1259 1260 /** 1261 * @ingroup simd_complex_batch_arithmetic 1262 * 1263 * Computes the product of the batches \c lhs and \c rhs. 1264 * @tparam X the actual type of batch. 1265 * @param lhs real batch involved in the product. 1266 * @param rhs batch involved in the product. 1267 * @return the result of the product. 1268 */ 1269 template <class X> operator *(const typename simd_batch_traits<X>::real_batch & lhs,const simd_complex_batch<X> & rhs)1270 inline X operator*(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs) 1271 { 1272 X tmp(lhs); 1273 return tmp *= rhs(); 1274 } 1275 1276 /** 1277 * @ingroup simd_complex_batch_arithmetic 1278 * 1279 * Computes the product of the batch \c lhs and the real scalar \c rhs. Equivalent to the 1280 * product of two batches where all the values of the second one are initialized to 1281 * \c rhs. 1282 * @tparam X the actual type of batch. 1283 * @param lhs batch involved in the product. 1284 * @param rhs real scalar involved in the product. 1285 * @return the result of the product. 1286 */ 1287 template <class X> operator *(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_value_type & rhs)1288 inline X operator*(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs) 1289 { 1290 X tmp(lhs()); 1291 return tmp *= X(rhs); 1292 } 1293 1294 /** 1295 * @ingroup simd_complex_batch_arithmetic 1296 * 1297 * Computes the product of the real scalar \c lhs and the batch \c rhs. Equivalent to the 1298 * difference of two batches where all the values of the first one are initialized to 1299 * \c rhs. 1300 * @tparam X the actual type of batch. 1301 * @param lhs real scalar involved in the product. 1302 * @param rhs batch involved in the product. 1303 * @return the result of the product. 1304 */ 1305 template <class X> operator *(const typename simd_batch_traits<X>::real_value_type & lhs,const simd_complex_batch<X> & rhs)1306 inline X operator*(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs) 1307 { 1308 X tmp(lhs); 1309 return tmp *= rhs(); 1310 } 1311 1312 /** 1313 * @ingroup simd_complex_batch_arithmetic 1314 * 1315 * Computes the division of the batch \c lhs by the batch \c rhs. 1316 * @tparam X the actual type of batch. 1317 * @param lhs batch involved in the division. 1318 * @param rhs batch involved in the division. 1319 * @return the result of the division. 1320 */ 1321 template <class X> operator /(const simd_complex_batch<X> & lhs,const simd_complex_batch<X> & rhs)1322 inline X operator/(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs) 1323 { 1324 X tmp(lhs()); 1325 return tmp /= rhs(); 1326 } 1327 1328 /** 1329 * @ingroup simd_complex_batch_arithmetic 1330 * 1331 * Computes the division of the batch \c lhs by the scalar \c rhs. Equivalent to the 1332 * division of two batches where all the values of the second one are initialized to 1333 * \c rhs. 1334 * @tparam X the actual type of batch. 1335 * @param lhs batch involved in the division. 1336 * @param rhs scalar involved in the division. 1337 * @return the result of the division. 1338 */ 1339 template <class X> operator /(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::value_type & rhs)1340 inline X operator/(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::value_type& rhs) 1341 { 1342 X tmp(lhs()); 1343 return tmp /= X(rhs); 1344 } 1345 1346 /** 1347 * @ingroup simd_complex_batch_arithmetic 1348 * 1349 * Computes the division of the scalar \c lhs and the batch \c rhs. Equivalent to the 1350 * difference of two batches where all the values of the first one are initialized to 1351 * \c rhs. 1352 * @tparam X the actual type of batch. 1353 * @param lhs scalar involved in the division. 1354 * @param rhs batch involved in the division. 1355 * @return the result of the division. 1356 */ 1357 template <class X> operator /(const typename simd_batch_traits<X>::value_type & lhs,const simd_complex_batch<X> & rhs)1358 inline X operator/(const typename simd_batch_traits<X>::value_type& lhs, const simd_complex_batch<X>& rhs) 1359 { 1360 X tmp(lhs); 1361 return tmp /= rhs(); 1362 } 1363 1364 /** 1365 * @ingroup simd_complex_batch_arithmetic 1366 * 1367 * Computes the division of the batch \c lhs by the batch \c rhs. 1368 * @tparam X the actual type of batch. 1369 * @param lhs batch involved in the division. 1370 * @param rhs real batch involved in the division. 1371 * @return the result of the division. 1372 */ 1373 template <class X> operator /(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_batch & rhs)1374 inline X operator/(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_batch& rhs) 1375 { 1376 X tmp(lhs()); 1377 return tmp /= X(rhs); 1378 } 1379 1380 /** 1381 * @ingroup simd_complex_batch_arithmetic 1382 * 1383 * Computes the division of the batch \c lhs by the batch \c rhs. 1384 * @tparam X the actual type of batch. 1385 * @param lhs real batch involved in the division. 1386 * @param rhs batch involved in the division. 1387 * @return the result of the division. 1388 */ 1389 template <class X> operator /(const typename simd_batch_traits<X>::real_batch & lhs,const simd_complex_batch<X> & rhs)1390 inline X operator/(const typename simd_batch_traits<X>::real_batch& lhs, const simd_complex_batch<X>& rhs) 1391 { 1392 X tmp(lhs); 1393 return tmp /= rhs(); 1394 } 1395 1396 /** 1397 * @ingroup simd_complex_batch_arithmetic 1398 * 1399 * Computes the division of the batch \c lhs by the real scalar \c rhs. Equivalent to the 1400 * division of two batches where all the values of the second one are initialized to 1401 * \c rhs. 1402 * @tparam X the actual type of batch. 1403 * @param lhs batch involved in the division. 1404 * @param rhs real scalar involved in the division. 1405 * @return the result of the division. 1406 */ 1407 template <class X> operator /(const simd_complex_batch<X> & lhs,const typename simd_batch_traits<X>::real_value_type & rhs)1408 inline X operator/(const simd_complex_batch<X>& lhs, const typename simd_batch_traits<X>::real_value_type& rhs) 1409 { 1410 X tmp(lhs()); 1411 return tmp /= X(rhs); 1412 } 1413 1414 /** 1415 * @ingroup simd_complex_batch_arithmetic 1416 * 1417 * Computes the division of the real scalar \c lhs and the batch \c rhs. Equivalent to the 1418 * difference of two batches where all the values of the first one are initialized to 1419 * \c rhs. 1420 * @tparam X the actual type of batch. 1421 * @param lhs real scalar involved in the division. 1422 * @param rhs batch involved in the division. 1423 * @return the result of the division. 1424 */ 1425 template <class X> operator /(const typename simd_batch_traits<X>::real_value_type & lhs,const simd_complex_batch<X> & rhs)1426 inline X operator/(const typename simd_batch_traits<X>::real_value_type& lhs, const simd_complex_batch<X>& rhs) 1427 { 1428 X tmp(lhs); 1429 return tmp /= rhs(); 1430 } 1431 1432 1433 /** 1434 * @defgroup simd_complex_batch_reducers Reducers 1435 */ 1436 1437 /** 1438 * @ingroup simd_complex_batch_reducers 1439 * 1440 * Adds all the scalars of the batch \c rhs. 1441 * @param rhs batch involved in the reduction 1442 * @return the result of the reduction. 1443 */ 1444 template <class X> 1445 inline typename simd_batch_traits<X>::value_type hadd(const simd_complex_batch<X> & rhs)1446 hadd(const simd_complex_batch<X>& rhs) 1447 { 1448 using value_type = typename simd_batch_traits<X>::value_type; 1449 return value_type(hadd(rhs.real()), hadd(rhs.imag())); 1450 } 1451 1452 /** 1453 * @defgroup simd_complex_batch_miscellaneous Miscellaneous 1454 */ 1455 1456 /** 1457 * @ingroup simd_complex_batch_miscellaneous 1458 * 1459 * Ternary operator for batches: selects values from the batches \c a or \c b 1460 * depending on the boolean values in \c cond. Equivalent to 1461 * \code{.cpp} 1462 * for(std::size_t i = 0; i < N; ++i) 1463 * res[i] = cond[i] ? a[i] : b[i]; 1464 * \endcode 1465 * @param cond batch condition. 1466 * @param a batch values for truthy condition. 1467 * @param b batch value for falsy condition. 1468 * @return the result of the selection. 1469 */ 1470 template <class X> select(const typename simd_batch_traits<X>::batch_bool_type & cond,const simd_complex_batch<X> & a,const simd_complex_batch<X> & b)1471 inline X select(const typename simd_batch_traits<X>::batch_bool_type& cond, 1472 const simd_complex_batch<X>& a, 1473 const simd_complex_batch<X>& b) 1474 { 1475 return X(select(cond.value(), a.real(), b.real()), select(cond.value(), a.imag(), b.imag())); 1476 } 1477 1478 /** 1479 * @defgroup simd_complex_batch_comparison Comparison operators 1480 */ 1481 1482 /** 1483 * @ingroup simd_complex_batch_comparison 1484 * 1485 * Element-wise equality comparison of batches \c lhs and \c rhs. 1486 * @param lhs batch involved in the comparison. 1487 * @param rhs batch involved in the comparison. 1488 * @return a boolean batch. 1489 */ 1490 template <class X> 1491 inline typename simd_batch_traits<X>::batch_bool_type operator ==(const simd_complex_batch<X> & lhs,const simd_complex_batch<X> & rhs)1492 operator==(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs) 1493 { 1494 return (lhs.real() == rhs.real()) && (lhs.imag() == rhs.imag()); 1495 } 1496 1497 /** 1498 * @ingroup simd_complex_batch_comparison 1499 * 1500 * Element-wise inequality comparison of batches \c lhs and \c rhs. 1501 * @param lhs batch involved in the comparison. 1502 * @param rhs batch involved in the comparison. 1503 * @return a boolean batch. 1504 */ 1505 template <class X> 1506 inline typename simd_batch_traits<X>::batch_bool_type operator !=(const simd_complex_batch<X> & lhs,const simd_complex_batch<X> & rhs)1507 operator!=(const simd_complex_batch<X>& lhs, const simd_complex_batch<X>& rhs) 1508 { 1509 return !(lhs == rhs); 1510 } 1511 1512 /** 1513 * Insert the batch \c rhs into the stream \c out. 1514 * @tparam X the actual type of batch. 1515 * @param out the output stream. 1516 * @param rhs the batch to output. 1517 * @return the output stream. 1518 */ 1519 template <class X> operator <<(std::ostream & out,const simd_complex_batch<X> & rhs)1520 inline std::ostream& operator<<(std::ostream& out, const simd_complex_batch<X>& rhs) 1521 { 1522 out << '('; 1523 std::size_t s = simd_complex_batch<X>::size; 1524 for (std::size_t i = 0; i < s - 1; ++i) 1525 { 1526 out << "(" << rhs()[i].real() << "," << rhs()[i].imag() << "), "; 1527 } 1528 out << "(" << rhs()[s - 1].real() << "," << rhs()[s - 1].imag() << "))"; 1529 return out; 1530 } 1531 } 1532 1533 #endif 1534 1535