| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361 |
- /***************************************************************************
- * Copyright (c) Sylvain Corlay and Johan Mabille and Wolf Vollprecht *
- * Copyright (c) QuantStack *
- * *
- * Distributed under the terms of the BSD 3-Clause License. *
- * *
- * The full license is in the file LICENSE, distributed with this software. *
- ****************************************************************************/
- #ifndef XTL_COMPLEX_HPP
- #define XTL_COMPLEX_HPP
- #if !defined(_MSC_VER)
- #include <cmath>
- using std::copysign;
- #endif
- #include <complex>
- #include <cstddef>
- #include <limits>
- #include <type_traits>
- #include <utility>
- #include <sstream>
- #include <string>
- #ifdef __CLING__
- #include <nlohmann/json.hpp>
- #endif
- #include "xclosure.hpp"
- #include "xtl_config.hpp"
- #include "xtype_traits.hpp"
- namespace xtl
- {
- template <class CTR, class CTI = CTR, bool ieee_compliant = false>
- class xcomplex;
- /**************
- * is_complex *
- **************/
- namespace detail
- {
- template <class T>
- struct is_complex : std::false_type
- {
- };
- template <class T>
- struct is_complex<std::complex<T>> : std::true_type
- {
- };
- }
- template <class T>
- struct is_complex
- {
- static constexpr bool value = detail::is_complex<std::decay_t<T>>::value;
- };
- /***************
- * is_xcomplex *
- ***************/
- namespace detail
- {
- template <class T>
- struct is_xcomplex : std::false_type
- {
- };
- template <class CTR, class CTI, bool B>
- struct is_xcomplex<xcomplex<CTR, CTI, B>> : std::true_type
- {
- };
- }
- template <class T>
- struct is_xcomplex
- {
- static constexpr bool value = detail::is_xcomplex<std::decay_t<T>>::value;
- };
- /******************
- * is_gen_complex *
- ******************/
- template <class T>
- using is_gen_complex = disjunction<is_complex<std::decay_t<T>>, is_xcomplex<std::decay_t<T>>>;
- /****************************
- * enable / disable complex *
- ****************************/
- template <class E, class R = void>
- using disable_xcomplex = std::enable_if_t<!is_gen_complex<E>::value, R>;
- template <class E, class R = void>
- using enable_xcomplex = std::enable_if_t<is_gen_complex<E>::value, R>;
- /*****************
- * enable_scalar *
- *****************/
- template <class E, class R = void>
- using enable_scalar = std::enable_if_t<xtl::is_arithmetic<E>::value, R>;
- /*******************
- * common_xcomplex *
- *******************/
- template <class CTR1, class CTI1, bool ieee1, class CTR2, class CTI2, bool ieee2>
- struct common_xcomplex
- {
- using type = xcomplex<std::common_type_t<CTR1, CTI1>, std::common_type_t<CTR2, CTI2>, ieee1 || ieee2>;
- };
- template <class CTR1, class CTI1, bool ieee1, class CTR2, class CTI2, bool ieee2>
- using common_xcomplex_t = typename common_xcomplex<CTR1, CTI1, ieee1, CTR2, CTI2, ieee2>::type;
- /**********************
- * temporary_xcomplex *
- **********************/
- template <class CTR, class CTI, bool ieee>
- struct temporary_xcomplex
- {
- using type = xcomplex<std::decay_t<CTR>, std::decay_t<CTI>, ieee>;
- };
- template <class CTR, class CTI, bool ieee>
- using temporary_xcomplex_t = typename temporary_xcomplex<CTR, CTI, ieee>::type;
- /************
- * xcomplex *
- ************/
- template <class CTR, class CTI, bool ieee_compliant>
- class xcomplex
- {
- public:
- static_assert(std::is_same<std::decay_t<CTR>, std::decay_t<CTI>>::value,
- "closure types must have the same value type");
- using value_type = std::common_type_t<CTR, CTI>;
- using self_type = xcomplex<CTR, CTI, ieee_compliant>;
- using temporary_type = temporary_xcomplex_t<CTR, CTI, ieee_compliant>;
- using real_reference = std::add_lvalue_reference_t<CTR>;
- using real_const_reference = std::add_lvalue_reference_t<std::add_const_t<CTR>>;
- using real_rvalue_reference = std::conditional_t<std::is_reference<CTR>::value, apply_cv_t<CTR, value_type>&, value_type>;
- using real_rvalue_const_reference = std::conditional_t<std::is_reference<CTR>::value, const value_type&, value_type>;
- using imag_reference = std::add_lvalue_reference_t<CTI>;
- using imag_const_reference = std::add_lvalue_reference_t<std::add_const_t<CTI>>;
- using imag_rvalue_reference = std::conditional_t<std::is_reference<CTI>::value, apply_cv_t<CTI, value_type>&, value_type>;
- using imag_rvalue_const_reference = std::conditional_t<std::is_reference<CTI>::value, const value_type&, value_type>;
- constexpr xcomplex() noexcept
- : m_real(), m_imag()
- {
- }
- template <class OCTR,
- std::enable_if_t<
- conjunction<
- negation<is_gen_complex<OCTR>>,
- std::is_constructible<CTR, OCTR&&>,
- std::is_convertible<OCTR&&, CTR>
- >::value,
- bool
- > = true>
- constexpr xcomplex(OCTR&& re) noexcept
- : m_real(std::forward<OCTR>(re)), m_imag()
- {
- }
- template <class OCTR,
- std::enable_if_t<
- conjunction<
- negation<is_gen_complex<OCTR>>,
- std::is_constructible<CTR, OCTR&&>,
- negation<std::is_convertible<OCTR&&, CTR>>
- >::value,
- bool
- > = true>
- explicit constexpr xcomplex(OCTR&& re) noexcept
- : m_real(std::forward<OCTR>(re)), m_imag()
- {
- }
- template <class OCTR, class OCTI>
- explicit constexpr xcomplex(OCTR&& re, OCTI&& im) noexcept
- : m_real(std::forward<OCTR>(re)), m_imag(std::forward<OCTI>(im))
- {
- }
- template <class OCTR, class OCTI, bool OB>
- explicit constexpr xcomplex(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept
- : m_real(rhs.real()), m_imag(rhs.imag())
- {
- }
- template <class OCTR, class OCTI, bool OB>
- explicit constexpr xcomplex(xcomplex<OCTR, OCTI, OB>&& rhs) noexcept
- : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag())
- {
- }
- template <class T>
- constexpr xcomplex(const std::complex<T>& rhs) noexcept
- : m_real(rhs.real()), m_imag(rhs.imag())
- {
- }
- template <class T>
- constexpr xcomplex(std::complex<T>&& rhs) noexcept
- : m_real(std::move(rhs).real()), m_imag(std::move(rhs).imag())
- {
- }
- template <class OCTR>
- disable_xcomplex<OCTR, self_type&> operator=(OCTR&& rhs) noexcept;
- template <class OCTR, class OCTI, bool OB>
- self_type& operator=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
- template <class OCTR, class OCTI, bool OB>
- self_type& operator=(xcomplex<OCTR, OCTI, OB>&& rhs) noexcept;
- operator std::complex<std::decay_t<CTR>>() const noexcept;
- template <class OCTR, class OCTI, bool OB>
- self_type& operator+=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
- template <class OCTR, class OCTI, bool OB>
- self_type& operator-=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
- template <class OCTR, class OCTI, bool OB>
- self_type& operator*=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
- template <class OCTR, class OCTI, bool OB>
- self_type& operator/=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept;
- template <class T>
- disable_xcomplex<T, self_type&> operator+=(const T& rhs) noexcept;
- template <class T>
- disable_xcomplex<T, self_type&> operator-=(const T& rhs) noexcept;
- template <class T>
- disable_xcomplex<T, self_type&> operator*=(const T& rhs) noexcept;
- template <class T>
- disable_xcomplex<T, self_type&> operator/=(const T& rhs) noexcept;
- real_reference real() & noexcept;
- real_rvalue_reference real() && noexcept;
- constexpr real_const_reference real() const & noexcept;
- constexpr real_rvalue_const_reference real() const && noexcept;
- imag_reference imag() & noexcept;
- imag_rvalue_reference imag() && noexcept;
- constexpr imag_const_reference imag() const & noexcept;
- constexpr imag_rvalue_const_reference imag() const && noexcept;
- xclosure_pointer<self_type&> operator&() & noexcept;
- xclosure_pointer<const self_type&> operator&() const & noexcept;
- xclosure_pointer<self_type> operator&() && noexcept;
- private:
- CTR m_real;
- CTI m_imag;
- };
- /**********************
- * xcomplex operators *
- **********************/
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- bool operator==(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- bool operator!=(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
- template <class OC, class OT, class CTR, class CTI, bool B>
- std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, const xcomplex<CTR, CTI, B>& c) noexcept;
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- operator+(const xcomplex<CTR, CTI, B>& rhs) noexcept;
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- operator-(const xcomplex<CTR, CTI, B>& rhs) noexcept;
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator+(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator+(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator+(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator-(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator-(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator-(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator*(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator*(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator*(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator/(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator/(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept;
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator/(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept;
- /*****************
- * real and imag *
- *****************/
- template <class E>
- decltype(auto) real(E&& e) noexcept;
- template <class E>
- decltype(auto) imag(E&& e) noexcept;
- /***************************
- * xcomplex free functions *
- ***************************/
- template <class CTR, class CTI, bool B>
- typename xcomplex<CTR, CTI, B>::value_type
- abs(const xcomplex<CTR, CTI, B>& rhs);
- template <class CTR, class CTI, bool B>
- typename xcomplex<CTR, CTI, B>::value_type
- arg(const xcomplex<CTR, CTI, B>& rhs);
- template <class CTR, class CTI, bool B>
- typename xcomplex<CTR, CTI, B>::value_type
- norm(const xcomplex<CTR, CTI, B>& rhs);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- conj(const xcomplex<CTR, CTI, B>& rhs);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- proj(const xcomplex<CTR, CTI, B>& rhs);
- /**********************************
- * xcomplex exponential functions *
- **********************************/
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- exp(const xcomplex<CTR, CTI, B>& rhs);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- log(const xcomplex<CTR, CTI, B>& rhs);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- log10(const xcomplex<CTR, CTI, B>& rhs);
- /****************************
- * xcomplex power functions *
- ****************************/
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- pow(const xcomplex<CTR1, CTI1, B1>& x, const xcomplex<CTR2, CTI2, B2>& y);
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- pow(const xcomplex<CTR, CTI, B>& x, const T& y);
- template <class CTR, class CTI, bool B, class T>
- enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- pow(const T& x, const xcomplex<CTR, CTI, B>& y);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- sqrt(const xcomplex<CTR, CTI, B>& x);
- /************************************
- * xcomplex trigonometric functions *
- ************************************/
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- sin(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- cos(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- tan(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- asin(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- acos(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- atan(const xcomplex<CTR, CTI, B>& x);
- /*********************************
- * xcomplex hyperbolic functions *
- *********************************/
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- sinh(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- cosh(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- tanh(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- asinh(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- acosh(const xcomplex<CTR, CTI, B>& x);
- template <class CTR, class CTI, bool B>
- temporary_xcomplex_t<CTR, CTI, B>
- atanh(const xcomplex<CTR, CTI, B>& x);
- /***************************
- * xcomplex implementation *
- ***************************/
- template <class CTR, class CTI, bool B>
- template <class OCTR>
- inline auto xcomplex<CTR, CTI, B>::operator=(OCTR&& rhs) noexcept -> disable_xcomplex<OCTR, self_type&>
- {
- m_real = std::forward<OCTR>(rhs);
- m_imag = std::decay_t<CTI>();
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class OCTR, class OCTI, bool OB>
- inline auto xcomplex<CTR, CTI, B>::operator=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
- {
- m_real = rhs.m_real;
- m_imag = rhs.m_imag;
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class OCTR, class OCTI, bool OB>
- inline auto xcomplex<CTR, CTI, B>::operator=(xcomplex<OCTR, OCTI, OB>&& rhs) noexcept -> self_type&
- {
- m_real = std::move(rhs.m_real);
- m_imag = std::move(rhs.m_imag);
- return *this;
- }
- template <class CTR, class CTI, bool B>
- inline xcomplex<CTR, CTI, B>::operator std::complex<std::decay_t<CTR>>() const noexcept
- {
- return std::complex<std::decay_t<CTR>>(m_real, m_imag);
- }
- template <class CTR, class CTI, bool B>
- template <class OCTR, class OCTI, bool OB>
- inline auto xcomplex<CTR, CTI, B>::operator+=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
- {
- m_real += rhs.m_real;
- m_imag += rhs.m_imag;
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class OCTR, class OCTI, bool OB>
- inline auto xcomplex<CTR, CTI, B>::operator-=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
- {
- m_real -= rhs.m_real;
- m_imag -= rhs.m_imag;
- return *this;
- }
- namespace detail
- {
- template <bool ieee_compliant>
- struct xcomplex_multiplier
- {
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- static auto mul(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
- {
- using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
- using value_type = typename return_type::value_type;
- value_type a = lhs.real();
- value_type b = lhs.imag();
- value_type c = rhs.real();
- value_type d = rhs.imag();
- return return_type(a*c - b*d, a*d + b*c);
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- static auto div(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
- {
- using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
- using value_type = typename return_type::value_type;
- value_type a = lhs.real();
- value_type b = lhs.imag();
- value_type c = rhs.real();
- value_type d = rhs.imag();
- value_type e = c*c + d*d;
- return return_type((c*a + d*b) / e, (c*b - d*a) / e);
- }
- };
- template <>
- struct xcomplex_multiplier<true>
- {
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- static auto mul(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
- {
- using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
- using value_type = typename return_type::value_type;
- value_type a = lhs.real();
- value_type b = lhs.imag();
- value_type c = rhs.real();
- value_type d = rhs.imag();
- value_type ac = a * c;
- value_type bd = b * d;
- value_type ad = a * d;
- value_type bc = b * c;
- value_type x = ac - bd;
- value_type y = ad + bc;
- if (std::isnan(x) && std::isnan(y))
- {
- bool recalc = false;
- if (std::isinf(a) || std::isinf(b))
- {
- a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a);
- b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b);
- if (std::isnan(c))
- {
- c = copysign(value_type(0), c);
- }
- if (std::isnan(d))
- {
- d = copysign(value_type(0), d);
- }
- recalc = true;
- }
- if (std::isinf(c) || std::isinf(d))
- {
- c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c);
- d = copysign(std::isinf(c) ? value_type(1) : value_type(0), d);
- if (std::isnan(a))
- {
- a = copysign(value_type(0), a);
- }
- if (std::isnan(b))
- {
- b = copysign(value_type(0), b);
- }
- recalc = true;
- }
- if (!recalc && (std::isinf(ac) || std::isinf(bd) || std::isinf(ad) || std::isinf(bc)))
- {
- if (std::isnan(a))
- {
- a = copysign(value_type(0), a);
- }
- if (std::isnan(b))
- {
- b = copysign(value_type(0), b);
- }
- if (std::isnan(c))
- {
- c = copysign(value_type(0), c);
- }
- if (std::isnan(d))
- {
- d = copysign(value_type(0), d);
- }
- recalc = true;
- }
- if (recalc)
- {
- x = std::numeric_limits<value_type>::infinity() * (a * c - b * d);
- y = std::numeric_limits<value_type>::infinity() * (a * d + b * c);
- }
- }
- return return_type(x, y);
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- static auto div(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs)
- {
- using return_type = temporary_xcomplex_t<CTR1, CTI1, B1>;
- using value_type = typename return_type::value_type;
- value_type a = lhs.real();
- value_type b = lhs.imag();
- value_type c = rhs.real();
- value_type d = rhs.imag();
- value_type logbw = std::logb(std::fmax(std::fabs(c), std::fabs(d)));
- int ilogbw = 0;
- if (std::isfinite(logbw))
- {
- ilogbw = static_cast<int>(logbw);
- c = std::scalbn(c, -ilogbw);
- d = std::scalbn(d, -ilogbw);
- }
- value_type denom = c*c + d*d;
- value_type x = std::scalbn((a*c + b*d) / denom, -ilogbw);
- value_type y = std::scalbn((b*c - a*d) / denom, -ilogbw);
- if (std::isnan(x) && std::isnan(y))
- {
- if ((denom == value_type(0)) && (!std::isnan(a) || !std::isnan(b)))
- {
- x = copysign(std::numeric_limits<value_type>::infinity(), c) * a;
- y = copysign(std::numeric_limits<value_type>::infinity(), c) * b;
- }
- else if ((std::isinf(a) || std::isinf(b)) && std::isfinite(c) && std::isfinite(d))
- {
- a = copysign(std::isinf(a) ? value_type(1) : value_type(0), a);
- b = copysign(std::isinf(b) ? value_type(1) : value_type(0), b);
- x = std::numeric_limits<value_type>::infinity() * (a*c + b*d);
- y = std::numeric_limits<value_type>::infinity() * (b*c - a*d);
- }
- else if (std::isinf(logbw) && logbw > value_type(0) && std::isfinite(a) && std::isfinite(b))
- {
- c = copysign(std::isinf(c) ? value_type(1) : value_type(0), c);
- d = copysign(std::isinf(d) ? value_type(1) : value_type(0), d);
- x = value_type(0) * (a*c + b*d);
- y = value_type(0) * (b*c - a*d);
- }
- }
- return std::complex<value_type>(x, y);
- }
- };
- }
- template <class CTR, class CTI, bool B>
- template <class OCTR, class OCTI, bool OB>
- inline auto xcomplex<CTR, CTI, B>::operator*=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
- {
- *this = detail::xcomplex_multiplier<B || OB>::mul(*this, rhs);
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class OCTR, class OCTI, bool OB>
- inline auto xcomplex<CTR, CTI, B>::operator/=(const xcomplex<OCTR, OCTI, OB>& rhs) noexcept -> self_type&
- {
- *this = detail::xcomplex_multiplier<B || OB>::div(*this, rhs);
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class T>
- inline auto xcomplex<CTR, CTI, B>::operator+=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
- {
- m_real += rhs;
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class T>
- inline auto xcomplex<CTR, CTI, B>::operator-=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
- {
- m_real -= rhs;
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class T>
- inline auto xcomplex<CTR, CTI, B>::operator*=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
- {
- m_real *= rhs;
- m_imag *= rhs;
- return *this;
- }
- template <class CTR, class CTI, bool B>
- template <class T>
- inline auto xcomplex<CTR, CTI, B>::operator/=(const T& rhs) noexcept -> disable_xcomplex<T, self_type&>
- {
- m_real /= rhs;
- m_imag /= rhs;
- return *this;
- }
- template <class CTR, class CTI, bool B>
- auto xcomplex<CTR, CTI, B>::real() & noexcept -> real_reference
- {
- return m_real;
- }
- template <class CTR, class CTI, bool B>
- auto xcomplex<CTR, CTI, B>::real() && noexcept -> real_rvalue_reference
- {
- return m_real;
- }
- template <class CTR, class CTI, bool B>
- constexpr auto xcomplex<CTR, CTI, B>::real() const & noexcept -> real_const_reference
- {
- return m_real;
- }
- template <class CTR, class CTI, bool B>
- constexpr auto xcomplex<CTR, CTI, B>::real() const && noexcept -> real_rvalue_const_reference
- {
- return m_real;
- }
- template <class CTR, class CTI, bool B>
- auto xcomplex<CTR, CTI, B>::imag() & noexcept -> imag_reference
- {
- return m_imag;
- }
- template <class CTR, class CTI, bool B>
- auto xcomplex<CTR, CTI, B>::imag() && noexcept -> imag_rvalue_reference
- {
- return m_imag;
- }
- template <class CTR, class CTI, bool B>
- constexpr auto xcomplex<CTR, CTI, B>::imag() const & noexcept -> imag_const_reference
- {
- return m_imag;
- }
- template <class CTR, class CTI, bool B>
- constexpr auto xcomplex<CTR, CTI, B>::imag() const && noexcept -> imag_rvalue_const_reference
- {
- return m_imag;
- }
- template <class CTR, class CTI, bool B>
- inline auto xcomplex<CTR, CTI, B>::operator&() & noexcept -> xclosure_pointer<self_type&>
- {
- return xclosure_pointer<self_type&>(*this);
- }
- template <class CTR, class CTI, bool B>
- inline auto xcomplex<CTR, CTI, B>::operator&() const & noexcept -> xclosure_pointer<const self_type&>
- {
- return xclosure_pointer<const self_type&>(*this);
- }
- template <class CTR, class CTI, bool B>
- inline auto xcomplex<CTR, CTI, B>::operator&() && noexcept -> xclosure_pointer<self_type>
- {
- return xclosure_pointer<self_type>(std::move(*this));
- }
- /*************************************
- * xcomplex operators implementation *
- *************************************/
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline bool operator==(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
- {
- return lhs.real() == rhs.real() && lhs.imag() == rhs.imag();
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline bool operator!=(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
- {
- return !(lhs == rhs);
- }
- template <class OC, class OT, class CTR, class CTI, bool B>
- inline std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, const xcomplex<CTR, CTI, B>& c) noexcept
- {
- out << "(" << c.real() << "," << c.imag() << ")";
- return out;
- }
- #ifdef __CLING__
- template <class CTR, class CTI, bool B>
- nlohmann::json mime_bundle_repr(const xcomplex<CTR, CTI, B>& c)
- {
- auto bundle = nlohmann::json::object();
- std::stringstream tmp;
- tmp << c;
- bundle["text/plain"] = tmp.str();
- return bundle;
- }
- #endif
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- operator+(const xcomplex<CTR, CTI, B>& rhs) noexcept
- {
- return rhs;
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- operator-(const xcomplex<CTR, CTI, B>& rhs) noexcept
- {
- return temporary_xcomplex_t<CTR, CTI, B>(-rhs.real(), -rhs.imag());
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator+(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
- {
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
- res += rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator+(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res += rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator+(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res += rhs;
- return res;
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator-(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
- {
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
- res -= rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator-(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res -= rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator-(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res -= rhs;
- return res;
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator*(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
- {
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
- res *= rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator*(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res *= rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator*(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res *= rhs;
- return res;
- }
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- operator/(const xcomplex<CTR1, CTI1, B1>& lhs, const xcomplex<CTR2, CTI2, B2>& rhs) noexcept
- {
- common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2> res(lhs);
- res /= rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator/(const xcomplex<CTR, CTI, B>& lhs, const T& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res /= rhs;
- return res;
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- operator/(const T& lhs, const xcomplex<CTR, CTI, B>& rhs) noexcept
- {
- temporary_xcomplex_t<CTR, CTI, B> res(lhs);
- res /= rhs;
- return res;
- }
- /***************************
- * xcomplex free functions *
- ***************************/
- template <class CTR, class CTI, bool B>
- inline typename xcomplex<CTR, CTI, B>::value_type
- abs(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::abs(std::complex<value_type>(rhs));
- }
- template <class CTR, class CTI, bool B>
- inline typename xcomplex<CTR, CTI, B>::value_type
- arg(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::arg(std::complex<value_type>(rhs));
- }
- template <class CTR, class CTI, bool B>
- inline typename xcomplex<CTR, CTI, B>::value_type
- norm(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::norm(std::complex<value_type>(rhs));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- conj(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::conj(std::complex<value_type>(rhs));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- proj(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::proj(std::complex<value_type>(rhs));
- }
- /*************************************************
- * xcomplex exponential functions implementation *
- *************************************************/
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- exp(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::exp(std::complex<value_type>(rhs));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- log(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::log(std::complex<value_type>(rhs));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- log10(const xcomplex<CTR, CTI, B>& rhs)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::log10(std::complex<value_type>(rhs));
- }
- /*******************************************
- * xcomplex power functions implementation *
- *******************************************/
- template <class CTR1, class CTI1, bool B1, class CTR2, class CTI2, bool B2>
- inline common_xcomplex_t<CTR1, CTI1, B1, CTR2, CTI2, B2>
- pow(const xcomplex<CTR1, CTI1, B1>& x, const xcomplex<CTR2, CTI2, B2>& y)
- {
- using value_type1 = typename xcomplex<CTR1, CTI1, B1>::value_type;
- using value_type2 = typename xcomplex<CTR2, CTI2, B2>::value_type;
- return std::pow(std::complex<value_type1>(x), std::complex<value_type2>(y));
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- pow(const xcomplex<CTR, CTI, B>& x, const T& y)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::pow(std::complex<value_type>(x), y);
- }
- template <class CTR, class CTI, bool B, class T>
- inline enable_scalar<T, temporary_xcomplex_t<CTR, CTI, B>>
- pow(const T& x, const xcomplex<CTR, CTI, B>& y)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::pow(x, std::complex<value_type>(y));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- sqrt(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename xcomplex<CTR, CTI, B>::value_type;
- return std::sqrt(std::complex<value_type>(x));
- }
- /***************************************************
- * xcomplex trigonometric functions implementation *
- ***************************************************/
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- sin(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::sin(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- cos(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::cos(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- tan(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::tan(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- asin(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::asin(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- acos(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::acos(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- atan(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::atan(std::complex<value_type>(x));
- }
- /************************************************
- * xcomplex hyperbolic functions implementation *
- ************************************************/
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- sinh(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::sinh(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- cosh(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::cosh(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- tanh(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::tanh(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- asinh(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::asinh(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- acosh(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::acosh(std::complex<value_type>(x));
- }
- template <class CTR, class CTI, bool B>
- inline temporary_xcomplex_t<CTR, CTI, B>
- atanh(const xcomplex<CTR, CTI, B>& x)
- {
- using value_type = typename temporary_xcomplex_t<CTR, CTI, B>::value_type;
- return std::atanh(std::complex<value_type>(x));
- }
- /*********************************
- * forward_offset implementation *
- *********************************/
- namespace detail
- {
- template <class T, class M>
- struct forward_type
- {
- using type = apply_cv_t<T, M>;
- };
- template <class T, class M>
- struct forward_type<T&, M>
- {
- using type = apply_cv_t<T, M>&;
- };
- template <class T, class M>
- using forward_type_t = typename forward_type<T, M>::type;
- }
- template <class M, std::size_t I, class T>
- constexpr detail::forward_type_t<T, M> forward_offset(T&& v) noexcept
- {
- using forward_type = detail::forward_type_t<T, M>;
- using cv_value_type = std::remove_reference_t<forward_type>;
- using byte_type = apply_cv_t<std::remove_reference_t<T>, char>;
- return static_cast<forward_type>(
- *reinterpret_cast<cv_value_type*>(
- reinterpret_cast<byte_type*>(&v) + I
- )
- );
- }
- /**********************************************
- * forward_real & forward_imag implementation *
- **********************************************/
- // forward_real
- template <class T>
- auto forward_real(T&& v)
- -> std::enable_if_t<!is_gen_complex<T>::value, detail::forward_type_t<T, T>> // real case -> forward
- {
- return static_cast<detail::forward_type_t<T, T>>(v);
- }
- template <class T>
- auto forward_real(T&& v)
- -> std::enable_if_t<is_complex<T>::value, detail::forward_type_t<T, typename std::decay_t<T>::value_type>> // complex case -> forward the real part
- {
- return forward_offset<typename std::decay_t<T>::value_type, 0>(v);
- }
- template <class T>
- auto forward_real(T&& v)
- -> std::enable_if_t<is_xcomplex<T>::value, decltype(std::forward<T>(v).real())>
- {
- return std::forward<T>(v).real();
- }
- // forward_imag
- template <class T>
- auto forward_imag(T &&)
- -> std::enable_if_t<!is_gen_complex<T>::value, std::decay_t<T>> // real case -> always return 0 by value
- {
- return 0;
- }
- template <class T>
- auto forward_imag(T&& v)
- -> std::enable_if_t<is_complex<T>::value, detail::forward_type_t<T, typename std::decay_t<T>::value_type>> // complex case -> forwards the imaginary part
- {
- using real_type = typename std::decay_t<T>::value_type;
- return forward_offset<real_type, sizeof(real_type)>(v);
- }
- template <class T>
- auto forward_imag(T&& v)
- -> std::enable_if_t<is_xcomplex<T>::value, decltype(std::forward<T>(v).imag())>
- {
- return std::forward<T>(v).imag();
- }
- /******************************
- * real & imag implementation *
- ******************************/
- template <class E>
- inline decltype(auto) real(E&& e) noexcept
- {
- return forward_real(std::forward<E>(e));
- }
- template <class E>
- inline decltype(auto) imag(E&& e) noexcept
- {
- return forward_imag(std::forward<E>(e));
- }
- /**********************
- * complex_value_type *
- **********************/
- template <class T>
- struct complex_value_type
- {
- using type = T;
- };
- template <class T>
- struct complex_value_type<std::complex<T>>
- {
- using type = T;
- };
- template <class CTR, class CTI, bool B>
- struct complex_value_type<xcomplex<CTR, CTI, B>>
- {
- using type = xcomplex<CTR, CTI, B>;
- };
- template <class T>
- using complex_value_type_t = typename complex_value_type<T>::type;
- /******************************************************
- * operator overloads for complex and closure wrapper *
- *****************************************************/
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator+(const std::complex<C>& c, const T& t)
- {
- std::complex<C> result(c);
- result += t;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator+(const T& t, const std::complex<C>& c)
- {
- std::complex<C> result(t);
- result += c;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator-(const std::complex<C>& c, const T& t)
- {
- std::complex<C> result(c);
- result -= t;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator-(const T& t, const std::complex<C>& c)
- {
- std::complex<C> result(t);
- result -= c;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator*(const std::complex<C>& c, const T& t)
- {
- std::complex<C> result(c);
- result *= t;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator*(const T& t, const std::complex<C>& c)
- {
- std::complex<C> result(t);
- result *= c;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator/(const std::complex<C>& c, const T& t)
- {
- std::complex<C> result(c);
- result /= t;
- return result;
- }
- template <class C, class T, std::enable_if_t<!xtl::is_complex<T>::value, int> = 0>
- std::complex<C> operator/(const T& t, const std::complex<C>& c)
- {
- std::complex<C> result(t);
- result /= c;
- return result;
- }
- }
- #endif
|