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