12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright 2011 John Maddock. Distributed under the Boost
- // Software License, Version 1.0. (See accompanying file
- // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_MATH_EXTENDED_REAL_HPP
- #define BOOST_MATH_EXTENDED_REAL_HPP
- #include <boost/config.hpp>
- #include <cstdint>
- #include <boost/assert.hpp>
- #include <boost/throw_exception.hpp>
- #include <boost/multiprecision/detail/precision.hpp>
- #include <boost/multiprecision/detail/generic_interconvert.hpp>
- #include <boost/multiprecision/detail/number_compare.hpp>
- #include <boost/multiprecision/traits/is_restricted_conversion.hpp>
- #include <boost/multiprecision/traits/is_complex.hpp>
- #include <boost/container_hash/hash.hpp>
- #include <istream> // stream operators
- #include <cstdio> // EOF
- #include <cctype> // isspace
- #include <functional> // std::hash
- #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
- #include <string_view>
- #endif
- namespace boost {
- namespace multiprecision {
- #ifdef BOOST_MSVC
- // warning C4127: conditional expression is constant
- // warning C4714: function marked as __forceinline not inlined
- #pragma warning(push)
- #pragma warning(disable : 4127 4714 6326)
- #endif
- template <class Backend, expression_template_option ExpressionTemplates>
- class number
- {
- using self_type = number<Backend, ExpressionTemplates>;
- public:
- using backend_type = Backend ;
- using value_type = typename component_type<self_type>::type;
- BOOST_MP_FORCEINLINE constexpr number() noexcept(noexcept(Backend())) {}
- BOOST_MP_FORCEINLINE constexpr number(const number& e) noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(e.m_backend) {}
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename std::enable_if<
- (boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
- #ifdef BOOST_HAS_FLOAT128
- && !std::is_same<V, __float128>::value
- #endif
- >::type* = 0)
- {
- m_backend = canonical_value(v);
- }
- template <class V>
- BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
- std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = 0)
- #ifndef BOOST_INTEL
- noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
- #endif
- : m_backend(canonical_value(v))
- {}
- template <class V>
- BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10, typename std::enable_if<(boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)
- #ifdef BOOST_HAS_FLOAT128
- && !std::is_same<V, __float128>::value
- #endif
- >::type* = 0)
- : m_backend(canonical_value(v), digits10)
- {}
- BOOST_MP_FORCEINLINE constexpr number(const number& e, unsigned digits10)
- noexcept(noexcept(Backend(std::declval<Backend const&>(), std::declval<unsigned>())))
- : m_backend(e.m_backend, digits10) {}
- template <class V>
- explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename std::enable_if<
- (boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && !detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = 0)
- noexcept(noexcept(std::declval<Backend&>() = std::declval<typename detail::canonical<V, Backend>::type const&>()))
- {
- m_backend = canonical_value(v);
- }
- template <class V>
- explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
- detail::is_explicitly_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && (detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value || !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value)>::type* = 0)
- noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
- : m_backend(canonical_value(v)) {}
- template <class V>
- explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, unsigned digits10, typename std::enable_if<(boost::multiprecision::detail::is_arithmetic<V>::value || std::is_same<std::string, V>::value || std::is_convertible<V, const char*>::value) && detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex) && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)>::type* = 0)
- : m_backend(canonical_value(v), digits10) {}
- template <expression_template_option ET>
- BOOST_MP_FORCEINLINE constexpr number(const number<Backend, ET>& val)
- noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(val.backend()) {}
- template <class Other, expression_template_option ET>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val,
- typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
- noexcept(noexcept(Backend(std::declval<Other const&>())))
- : m_backend(val.backend()) {}
- template <class Other, expression_template_option ET>
- explicit BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
- (!detail::is_explicitly_convertible<Other, Backend>::value)>::type* = 0)
- {
- //
- // Attempt a generic interconvertion:
- //
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard_1(val);
- detail::scoped_default_precision<number<Other, ET> > precision_guard_2(val);
- using detail::generic_interconvert;
- generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
- }
- template <class Other, expression_template_option ET>
- explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
- (detail::is_explicitly_convertible<Other, Backend>::value && (detail::is_restricted_conversion<Other, Backend>::value || !std::is_convertible<Other, Backend>::value))>::type* = 0) noexcept(noexcept(Backend(std::declval<Other const&>())))
- : m_backend(val.backend()) {}
- template <class V, class U>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
- typename std::enable_if<(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value && !std::is_same<typename component_type<self_type>::type, self_type>::value)>::type* = 0)
- {
- using default_ops::assign_components;
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
- assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
- }
- template <class V, class U>
- BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
- typename std::enable_if<
- (std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<typename component_type<self_type>::type, self_type>::value && !std::is_same<V, self_type>::value && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = 0)
- {
- using default_ops::assign_components;
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
- assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
- }
- #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
- //
- // Support for new types in C++17
- //
- template <class Traits>
- explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view)
- {
- using default_ops::assign_from_string_view;
- assign_from_string_view(this->backend(), view);
- }
- template <class Traits>
- explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view_x, const std::basic_string_view<char, Traits>& view_y)
- {
- using default_ops::assign_from_string_view;
- assign_from_string_view(this->backend(), view_x, view_y);
- }
- template <class Traits>
- explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& v, unsigned digits10)
- : m_backend(canonical_value(v), digits10) {}
- template <class Traits>
- BOOST_MP_CXX14_CONSTEXPR number& assign(const std::basic_string_view<char, Traits>& view)
- {
- using default_ops::assign_from_string_view;
- assign_from_string_view(this->backend(), view);
- return *this;
- }
- #endif
- template <class V, class U>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
- typename std::enable_if<(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value && !std::is_same<typename component_type<self_type>::type, self_type>::value)>::type* = 0)
- : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10)
- {}
- template <class V, class U>
- BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
- typename std::enable_if<((std::is_constructible<value_type, V>::value || std::is_convertible<V, std::string>::value) && (std::is_constructible<value_type, U>::value || std::is_convertible<U, std::string>::value) && !std::is_same<typename component_type<self_type>::type, self_type>::value) && !(is_convertible<V, value_type>::value && is_convertible<U, value_type>::value)>::type* = 0)
- : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10) {}
- template <class Other, expression_template_option ET>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& v1, const number<Other, ET>& v2, typename std::enable_if<std::is_convertible<Other, Backend>::value>::type* = 0)
- {
- using default_ops::assign_components;
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
- assign_components(m_backend, v1.backend(), v2.backend());
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(e);
- return *this = std::move(t);
- }
- do_assign(e, tag_type());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t;
- t.assign(e);
- return *this = std::move(t);
- }
- do_assign(e, tag_type());
- return *this;
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(const number& e)
- noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend const&>()))
- {
- m_backend = e.m_backend;
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator=(const V& v)
- noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
- {
- m_backend = canonical_value(v);
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v)
- noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
- {
- m_backend = canonical_value(v);
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, unsigned digits10)
- noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
- {
- number t(v, digits10);
- return *this = t;
- }
- template <class Other, expression_template_option ET>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>::value, number<Backend, ExpressionTemplates>&>::type
- assign(const number<Other, ET>& v)
- {
- //
- // Attempt a generic interconvertion:
- //
- using detail::generic_interconvert;
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v);
- detail::scoped_default_precision<number<Other, ET> > precision_guard2(v);
- //
- // If the current precision of *this differs from that of value v, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(v);
- return *this = std::move(t);
- }
- generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0)
- {
- //
- // No preicsion guard here, we already have one in operator=
- //
- *this = e;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- explicit BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
- typename std::enable_if<!std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value && boost::multiprecision::detail::is_explicitly_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value>::type* = 0)
- {
- //
- // No precision guard as assign has one already:
- //
- assign(e);
- }
- // rvalues:
- BOOST_MP_FORCEINLINE constexpr number(number&& r)
- noexcept(noexcept(Backend(std::declval<Backend>())))
- : m_backend(static_cast<Backend&&>(r.m_backend))
- {}
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(number&& r) noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend>()))
- {
- m_backend = static_cast<Backend&&>(r.m_backend);
- return *this;
- }
- template <class Other, expression_template_option ET>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(number<Other, ET>&& val,
- typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = 0)
- noexcept(noexcept(Backend(std::declval<Other const&>())))
- : m_backend(static_cast<number<Other, ET>&&>(val).backend()) {}
- template <class Other, expression_template_option ET>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value), number&>::type
- operator=(number<Other, ET>&& val)
- noexcept(noexcept(Backend(std::declval<Other const&>())))
- {
- m_backend = std::move(val).backend();
- return *this;
- }
- BOOST_MP_CXX14_CONSTEXPR number& operator+=(const self_type& val)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this + val);
- return *this = std::move(t);
- }
- do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator+=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- // Create a copy if e contains this, but not if we're just doing a
- // x += x
- if ((contains_self(e) && !is_self(e)))
- {
- self_type temp(e);
- do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_add(e, tag());
- }
- return *this;
- }
- template <class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this + e);
- return *this = std::move(t);
- }
- //
- // Fused multiply-add:
- //
- using default_ops::eval_multiply_add;
- eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
- return *this;
- }
- template <class V>
- typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v)
- {
- using default_ops::eval_add;
- eval_add(m_backend, canonical_value(v));
- return *this;
- }
- BOOST_MP_CXX14_CONSTEXPR number& operator-=(const self_type& val)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this - val);
- return *this = std::move(t);
- }
- do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator-=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- // Create a copy if e contains this:
- if (contains_self(e))
- {
- self_type temp(e);
- do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator-=(const V& v)
- {
- using default_ops::eval_subtract;
- eval_subtract(m_backend, canonical_value(v));
- return *this;
- }
- template <class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this - e);
- return *this = std::move(t);
- }
- //
- // Fused multiply-subtract:
- //
- using default_ops::eval_multiply_subtract;
- eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
- return *this;
- }
- BOOST_MP_CXX14_CONSTEXPR number& operator*=(const self_type& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this * e);
- return *this = std::move(t);
- }
- do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator*=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- // Create a temporary if the RHS references *this, but not
- // if we're just doing an x *= x;
- if ((contains_self(e) && !is_self(e)))
- {
- self_type temp(e);
- do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator*=(const V& v)
- {
- using default_ops::eval_multiply;
- eval_multiply(m_backend, canonical_value(v));
- return *this;
- }
- BOOST_MP_CXX14_CONSTEXPR number& operator%=(const self_type& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this % e);
- return *this = std::move(t);
- }
- do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator%=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- // Create a temporary if the RHS references *this:
- if (contains_self(e))
- {
- self_type temp(e);
- do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator%=(const V& v)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- using default_ops::eval_modulus;
- eval_modulus(m_backend, canonical_value(v));
- return *this;
- }
- //
- // These operators are *not* proto-ized.
- // The issue is that the increment/decrement must happen
- // even if the result of the operator *is never used*.
- // Possibly we could modify our expression wrapper to
- // execute the increment/decrement on destruction, but
- // correct implementation will be tricky, so defered for now...
- //
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator++()
- {
- using default_ops::eval_increment;
- eval_increment(m_backend);
- return *this;
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator--()
- {
- using default_ops::eval_decrement;
- eval_decrement(m_backend);
- return *this;
- }
- inline BOOST_MP_CXX14_CONSTEXPR number operator++(int)
- {
- using default_ops::eval_increment;
- self_type temp(*this);
- eval_increment(m_backend);
- return temp;
- }
- inline BOOST_MP_CXX14_CONSTEXPR number operator--(int)
- {
- using default_ops::eval_decrement;
- self_type temp(*this);
- eval_decrement(m_backend);
- return temp;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator<<=(V val)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types");
- detail::check_shift_range(val, std::integral_constant<bool, (sizeof(V) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<V>::value && boost::multiprecision::detail::is_integral<V>::value > ());
- eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator>>=(V val)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types");
- detail::check_shift_range(val, std::integral_constant<bool, (sizeof(V) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<V>::value && boost::multiprecision::detail::is_integral<V>::value>());
- eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
- return *this;
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator/=(const self_type& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- //
- // If the current precision of *this differs from that of expression e, then we
- // create a temporary (which will have the correct precision thanks to precision_guard)
- // and then move the result into *this. In C++17 we add a leading "if constexpr"
- // which causes this code to be eliminated in the common case that this type is
- // not actually variable precision. Pre C++17 this code should still be mostly
- // optimised away, but we can't prevent instantiation of the dead code leading
- // to longer build and possibly link times.
- //
- BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
- if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of(*this))
- {
- number t(*this / e);
- return *this = std::move(t);
- }
- do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator/=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
- // Create a temporary if the RHS references *this:
- if (contains_self(e))
- {
- self_type temp(e);
- do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator/=(const V& v)
- {
- using default_ops::eval_divide;
- eval_divide(m_backend, canonical_value(v));
- return *this;
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator&=(const self_type& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
- do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator&=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
- // Create a temporary if the RHS references *this, but not
- // if we're just doing an x &= x;
- if (contains_self(e) && !is_self(e))
- {
- self_type temp(e);
- do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator&=(const V& v)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
- using default_ops::eval_bitwise_and;
- eval_bitwise_and(m_backend, canonical_value(v));
- return *this;
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator|=(const self_type& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
- do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator|=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
- // Create a temporary if the RHS references *this, but not
- // if we're just doing an x |= x;
- if (contains_self(e) && !is_self(e))
- {
- self_type temp(e);
- do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator|=(const V& v)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
- using default_ops::eval_bitwise_or;
- eval_bitwise_or(m_backend, canonical_value(v));
- return *this;
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator^=(const self_type& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
- do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal());
- return *this;
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, self_type>::value, number&>::type operator^=(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
- if (contains_self(e))
- {
- self_type temp(e);
- do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- else
- {
- do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
- }
- return *this;
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
- operator^=(const V& v)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
- using default_ops::eval_bitwise_xor;
- eval_bitwise_xor(m_backend, canonical_value(v));
- return *this;
- }
- //
- // swap:
- //
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(self_type& other) noexcept(noexcept(std::declval<Backend>().swap(std::declval<Backend&>())))
- {
- m_backend.swap(other.backend());
- }
- //
- // Zero and sign:
- //
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool is_zero() const
- {
- using default_ops::eval_is_zero;
- return eval_is_zero(m_backend);
- }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int sign() const
- {
- using default_ops::eval_get_sign;
- return eval_get_sign(m_backend);
- }
- //
- // String conversion functions:
- //
- std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0)) const
- {
- return m_backend.str(digits, f);
- }
- template <class Archive>
- void serialize(Archive& ar, const unsigned int /*version*/)
- {
- ar& boost::make_nvp("backend", m_backend);
- }
- private:
- template <class T>
- BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(T* result) const
- {
- using default_ops::eval_convert_to;
- eval_convert_to(result, m_backend);
- }
- template <class B2, expression_template_option ET>
- BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(number<B2, ET>* result) const
- {
- result->assign(*this);
- }
- BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(std::string* result) const
- {
- *result = this->str();
- }
- public:
- template <class T>
- BOOST_MP_CXX14_CONSTEXPR T convert_to() const
- {
- T result = T();
- convert_to_imp(&result);
- return result;
- }
- //
- // Use in boolean context, and explicit conversion operators:
- //
- #if BOOST_WORKAROUND(BOOST_MSVC, < 1900) || (defined(__apple_build_version__) && BOOST_WORKAROUND(__clang_major__, < 9))
- template <class T>
- #else
- template <class T, class = typename std::enable_if<!(std::is_constructible<T, self_type const&>::value || !std::is_default_constructible<T>::value || (!boost::multiprecision::detail::is_arithmetic<T>::value && !boost::multiprecision::detail::is_complex<T>::value)), T>::type>
- #endif
- explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
- {
- return this->template convert_to<T>();
- }
- BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
- {
- return !is_zero();
- }
- //
- // Default precision:
- //
- static BOOST_MP_CXX14_CONSTEXPR unsigned default_precision() noexcept
- {
- return Backend::default_precision();
- }
- static BOOST_MP_CXX14_CONSTEXPR void default_precision(unsigned digits10)
- {
- Backend::default_precision(digits10);
- }
- BOOST_MP_CXX14_CONSTEXPR unsigned precision() const noexcept
- {
- return m_backend.precision();
- }
- BOOST_MP_CXX14_CONSTEXPR void precision(unsigned digits10)
- {
- m_backend.precision(digits10);
- }
- //
- // Comparison:
- //
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int compare(const number<Backend, ExpressionTemplates>& o) const
- noexcept(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
- {
- return m_backend.compare(o.m_backend);
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value && (number_category<Backend>::value != number_kind_complex), int>::type compare(const V& o) const
- {
- using default_ops::eval_get_sign;
- if (o == 0)
- return eval_get_sign(m_backend);
- return m_backend.compare(canonical_value(o));
- }
- template <class V>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<V>::value && (number_category<Backend>::value == number_kind_complex), int>::type compare(const V& o) const
- {
- using default_ops::eval_get_sign;
- return m_backend.compare(canonical_value(o));
- }
- //
- // Direct access to the underlying backend:
- //
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() & noexcept
- {
- return m_backend;
- }
- BOOST_MP_FORCEINLINE constexpr const Backend& backend() const& noexcept { return m_backend; }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend&& backend() && noexcept { return static_cast<Backend&&>(m_backend); }
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend const&& backend() const&& noexcept { return static_cast<Backend const&&>(m_backend); }
- //
- // Complex number real and imag:
- //
- BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
- real() const
- {
- using default_ops::eval_real;
- detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
- typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
- eval_real(result.backend(), backend());
- return result;
- }
- BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
- imag() const
- {
- using default_ops::eval_imag;
- detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
- typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
- eval_imag(result.backend(), backend());
- return result;
- }
- template <class T>
- inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value, self_type&>::type real(const T& val)
- {
- using default_ops::eval_set_real;
- eval_set_real(backend(), canonical_value(val));
- return *this;
- }
- template <class T>
- inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value && number_category<self_type>::value == number_kind_complex, self_type&>::type imag(const T& val)
- {
- using default_ops::eval_set_imag;
- eval_set_imag(backend(), canonical_value(val));
- return *this;
- }
- private:
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
- do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
- {
- // The result of the expression isn't the same type as this -
- // create a temporary result and assign it to *this:
- using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
- temp_type t(e);
- *this = std::move(t);
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
- do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
- {
- // The result of the expression isn't the same type as this -
- // create a temporary result and assign it to *this:
- using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
- temp_type t(e);
- this->assign(t);
- }
- template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, true>&)
- {
- do_assign(e, tag());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::add_immediates&)
- {
- using default_ops::eval_add;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::subtract_immediates&)
- {
- using default_ops::eval_subtract;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_immediates&)
- {
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_add&)
- {
- using default_ops::eval_multiply_add;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_subtract&)
- {
- using default_ops::eval_multiply_subtract;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divide_immediates&)
- {
- using default_ops::eval_divide;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::negate&)
- {
- using left_type = typename Exp::left_type;
- do_assign(e.left(), typename left_type::tag_type());
- m_backend.negate();
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::plus&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- constexpr int const left_depth = left_type::depth;
- constexpr int const right_depth = right_type::depth;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && br)
- {
- self_type temp(e);
- temp.m_backend.swap(this->m_backend);
- }
- else if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_add(e.right(), typename right_type::tag_type());
- }
- else if (br && is_self(e.right()))
- {
- // Ignore the right node, it's *this, just add the left:
- do_add(e.left(), typename left_type::tag_type());
- }
- else if (!br && (bl || (left_depth >= right_depth)))
- { // br is always false, but if bl is true we must take the this branch:
- do_assign(e.left(), typename left_type::tag_type());
- do_add(e.right(), typename right_type::tag_type());
- }
- else
- {
- do_assign(e.right(), typename right_type::tag_type());
- do_add(e.left(), typename left_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::minus&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- constexpr int const left_depth = left_type::depth;
- constexpr int const right_depth = right_type::depth;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && br)
- {
- self_type temp(e);
- temp.m_backend.swap(this->m_backend);
- }
- else if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just subtract the right:
- do_subtract(e.right(), typename right_type::tag_type());
- }
- else if (br && is_self(e.right()))
- {
- // Ignore the right node, it's *this, just subtract the left and negate the result:
- do_subtract(e.left(), typename left_type::tag_type());
- m_backend.negate();
- }
- else if (!br && (bl || (left_depth >= right_depth)))
- { // br is always false, but if bl is true we must take the this branch:
- do_assign(e.left(), typename left_type::tag_type());
- do_subtract(e.right(), typename right_type::tag_type());
- }
- else
- {
- do_assign(e.right(), typename right_type::tag_type());
- do_subtract(e.left(), typename left_type::tag_type());
- m_backend.negate();
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiplies&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- constexpr int const left_depth = left_type::depth;
- constexpr int const right_depth = right_type::depth;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && br)
- {
- self_type temp(e);
- temp.m_backend.swap(this->m_backend);
- }
- else if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_multiplies(e.right(), typename right_type::tag_type());
- }
- else if (br && is_self(e.right()))
- {
- // Ignore the right node, it's *this, just add the left:
- do_multiplies(e.left(), typename left_type::tag_type());
- }
- else if (!br && (bl || (left_depth >= right_depth)))
- { // br is always false, but if bl is true we must take the this branch:
- do_assign(e.left(), typename left_type::tag_type());
- do_multiplies(e.right(), typename right_type::tag_type());
- }
- else
- {
- do_assign(e.right(), typename right_type::tag_type());
- do_multiplies(e.left(), typename left_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divides&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_divide(e.right(), typename right_type::tag_type());
- }
- else if (br)
- {
- self_type temp(e);
- temp.m_backend.swap(this->m_backend);
- }
- else
- {
- do_assign(e.left(), typename left_type::tag_type());
- do_divide(e.right(), typename right_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus&)
- {
- //
- // This operation is only valid for integer backends:
- //
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_modulus(e.right(), typename right_type::tag_type());
- }
- else if (br)
- {
- self_type temp(e);
- temp.m_backend.swap(this->m_backend);
- }
- else
- {
- do_assign(e.left(), typename left_type::tag_type());
- do_modulus(e.right(), typename right_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus_immediates&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- using default_ops::eval_modulus;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and&)
- {
- //
- // This operation is only valid for integer backends:
- //
- static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- constexpr int const left_depth = left_type::depth;
- constexpr int const right_depth = right_type::depth;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_bitwise_and(e.right(), typename right_type::tag_type());
- }
- else if (br && is_self(e.right()))
- {
- do_bitwise_and(e.left(), typename left_type::tag_type());
- }
- else if (!br && (bl || (left_depth >= right_depth)))
- {
- do_assign(e.left(), typename left_type::tag_type());
- do_bitwise_and(e.right(), typename right_type::tag_type());
- }
- else
- {
- do_assign(e.right(), typename right_type::tag_type());
- do_bitwise_and(e.left(), typename left_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
- using default_ops::eval_bitwise_and;
- eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or&)
- {
- //
- // This operation is only valid for integer backends:
- //
- static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- constexpr int const left_depth = left_type::depth;
- constexpr int const right_depth = right_type::depth;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_bitwise_or(e.right(), typename right_type::tag_type());
- }
- else if (br && is_self(e.right()))
- {
- do_bitwise_or(e.left(), typename left_type::tag_type());
- }
- else if (!br && (bl || (left_depth >= right_depth)))
- {
- do_assign(e.left(), typename left_type::tag_type());
- do_bitwise_or(e.right(), typename right_type::tag_type());
- }
- else
- {
- do_assign(e.right(), typename right_type::tag_type());
- do_bitwise_or(e.left(), typename left_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
- using default_ops::eval_bitwise_or;
- eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor&)
- {
- //
- // This operation is only valid for integer backends:
- //
- static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- constexpr int const left_depth = left_type::depth;
- constexpr int const right_depth = right_type::depth;
- bool bl = contains_self(e.left());
- bool br = contains_self(e.right());
- if (bl && is_self(e.left()))
- {
- // Ignore the left node, it's *this, just add the right:
- do_bitwise_xor(e.right(), typename right_type::tag_type());
- }
- else if (br && is_self(e.right()))
- {
- do_bitwise_xor(e.left(), typename left_type::tag_type());
- }
- else if (!br && (bl || (left_depth >= right_depth)))
- {
- do_assign(e.left(), typename left_type::tag_type());
- do_bitwise_xor(e.right(), typename right_type::tag_type());
- }
- else
- {
- do_assign(e.right(), typename right_type::tag_type());
- do_bitwise_xor(e.left(), typename left_type::tag_type());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
- using default_ops::eval_bitwise_xor;
- eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::terminal&)
- {
- if (!is_self(e))
- {
- m_backend = canonical_value(e.value());
- }
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::function&)
- {
- using tag_type = typename Exp::arity;
- boost::multiprecision::detail::maybe_promote_precision(this);
- do_assign_function(e, tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_left&)
- {
- // We can only shift by an integer value, not an arbitrary expression:
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type ;
- using right_arity = typename right_type::arity;
- static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
- using right_value_type = typename right_type::result_type;
- static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
- using tag_type = typename left_type::tag_type;
- do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_right&)
- {
- // We can only shift by an integer value, not an arbitrary expression:
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type ;
- using right_arity = typename right_type::arity;
- static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
- using right_value_type = typename right_type::result_type;
- static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
- using tag_type = typename left_type::tag_type;
- do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_complement&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
- using default_ops::eval_complement;
- self_type temp(e.left());
- eval_complement(m_backend, temp.backend());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::complement_immediates&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
- using default_ops::eval_complement;
- eval_complement(m_backend, canonical_value(e.left().value()));
- }
- template <class Exp, class Val>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
- using default_ops::eval_right_shift;
- detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
- eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
- }
- template <class Exp, class Val>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
- using default_ops::eval_left_shift;
- detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
- eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
- }
- template <class Exp, class Val, class Tag>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
- using default_ops::eval_right_shift;
- self_type temp(e);
- detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
- eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
- }
- template <class Exp, class Val, class Tag>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
- using default_ops::eval_left_shift;
- self_type temp(e);
- detail::check_shift_range(val, std::integral_constant<bool, (sizeof(Val) > sizeof(std::size_t))>(), std::integral_constant<bool, boost::multiprecision::detail::is_signed<Val>::value&& boost::multiprecision::detail::is_integral<Val>::value>());
- eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 1>&)
- {
- e.left().value()(&m_backend);
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 2>&)
- {
- using right_type = typename Exp::right_type ;
- using tag_type = typename right_type::tag_type;
- do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
- }
- template <class F, class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
- {
- f(m_backend, function_arg_value(val));
- }
- template <class F, class Exp, class Tag>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const Tag&)
- {
- typename Exp::result_type t(val);
- f(m_backend, t.backend());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 3>&)
- {
- using middle_type = typename Exp::middle_type ;
- using tag_type = typename middle_type::tag_type;
- using end_type = typename Exp::right_type ;
- using end_tag = typename end_type::tag_type ;
- do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
- }
- template <class F, class Exp1, class Exp2>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
- {
- f(m_backend, function_arg_value(val1), function_arg_value(val2));
- }
- template <class F, class Exp1, class Exp2, class Tag1>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
- {
- typename Exp1::result_type temp1(val1);
- f(m_backend, std::move(temp1.backend()), function_arg_value(val2));
- }
- template <class F, class Exp1, class Exp2, class Tag2>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
- {
- typename Exp2::result_type temp2(val2);
- f(m_backend, function_arg_value(val1), std::move(temp2.backend()));
- }
- template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
- {
- typename Exp1::result_type temp1(val1);
- typename Exp2::result_type temp2(val2);
- f(m_backend, std::move(temp1.backend()), std::move(temp2.backend()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 4>&)
- {
- using left_type = typename Exp::left_middle_type ;
- using left_tag_type = typename left_type::tag_type ;
- using middle_type = typename Exp::right_middle_type;
- using middle_tag_type = typename middle_type::tag_type ;
- using right_type = typename Exp::right_type ;
- using right_tag_type = typename right_type::tag_type ;
- do_assign_function_3a(e.left().value(), e.left_middle_ref(), e.right_middle_ref(), e.right_ref(), left_tag_type(), middle_tag_type(), right_tag_type());
- }
- template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag2& t2, const Tag3& t3)
- {
- do_assign_function_3b(f, val1, val2, val3, t2, t3);
- }
- template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3a(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag1&, const Tag2& t2, const Tag3& t3)
- {
- typename Exp1::result_type t(val1);
- do_assign_function_3b(f, std::move(t), val2, val3, t2, t3);
- }
- template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&, const Tag3& t3)
- {
- do_assign_function_3c(f, val1, val2, val3, t3);
- }
- template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3b(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag2& /*t2*/, const Tag3& t3)
- {
- typename Exp2::result_type t(val2);
- do_assign_function_3c(f, val1, std::move(t), val3, t3);
- }
- template <class F, class Exp1, class Exp2, class Exp3>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
- {
- f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
- }
- template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
- BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
- {
- typename Exp3::result_type t(val3);
- do_assign_function_3c(f, val1, val2, std::move(t), detail::terminal());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::terminal&)
- {
- using default_ops::eval_add;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_add(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::negate&)
- {
- using left_type = typename Exp::left_type;
- boost::multiprecision::detail::maybe_promote_precision(this);
- do_subtract(e.left(), typename left_type::tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::plus&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_add(e.left(), typename left_type::tag_type());
- do_add(e.right(), typename right_type::tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::minus&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_add(e.left(), typename left_type::tag_type());
- do_subtract(e.right(), typename right_type::tag_type());
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const unknown&)
- {
- self_type temp(e);
- do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::add_immediates&)
- {
- using default_ops::eval_add;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_add(m_backend, canonical_value(e.left().value()));
- eval_add(m_backend, canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::subtract_immediates&)
- {
- using default_ops::eval_add;
- using default_ops::eval_subtract;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_add(m_backend, canonical_value(e.left().value()));
- eval_subtract(m_backend, canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::terminal&)
- {
- using default_ops::eval_subtract;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_subtract(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::negate&)
- {
- using left_type = typename Exp::left_type;
- do_add(e.left(), typename left_type::tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::plus&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_subtract(e.left(), typename left_type::tag_type());
- do_subtract(e.right(), typename right_type::tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::minus&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_subtract(e.left(), typename left_type::tag_type());
- do_add(e.right(), typename right_type::tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::add_immediates&)
- {
- using default_ops::eval_subtract;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_subtract(m_backend, canonical_value(e.left().value()));
- eval_subtract(m_backend, canonical_value(e.right().value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::subtract_immediates&)
- {
- using default_ops::eval_add;
- using default_ops::eval_subtract;
- eval_subtract(m_backend, canonical_value(e.left().value()));
- eval_add(m_backend, canonical_value(e.right().value()));
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const unknown&)
- {
- self_type temp(e);
- do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::terminal&)
- {
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_multiply(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::negate&)
- {
- using left_type = typename Exp::left_type;
- do_multiplies(e.left(), typename left_type::tag_type());
- m_backend.negate();
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiplies&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_multiplies(e.left(), typename left_type::tag_type());
- do_multiplies(e.right(), typename right_type::tag_type());
- }
- //
- // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
- // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
- //
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
- do_multiplies(const Exp& e, const detail::divides&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_multiplies(e.left(), typename left_type::tag_type());
- do_divide(e.right(), typename right_type::tag_type());
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiply_immediates&)
- {
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_multiply(m_backend, canonical_value(e.left().value()));
- eval_multiply(m_backend, canonical_value(e.right().value()));
- }
- //
- // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
- // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
- //
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
- do_multiplies(const Exp& e, const detail::divide_immediates&)
- {
- using default_ops::eval_divide;
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_multiply(m_backend, canonical_value(e.left().value()));
- eval_divide(m_backend, canonical_value(e.right().value()));
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const unknown&)
- {
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- self_type temp(e);
- eval_multiply(m_backend, temp.m_backend);
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::terminal&)
- {
- using default_ops::eval_divide;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_divide(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::negate&)
- {
- using left_type = typename Exp::left_type;
- do_divide(e.left(), typename left_type::tag_type());
- m_backend.negate();
- }
- //
- // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
- // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
- //
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
- do_divide(const Exp& e, const detail::multiplies&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_divide(e.left(), typename left_type::tag_type());
- do_divide(e.right(), typename right_type::tag_type());
- }
- //
- // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
- // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
- //
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
- do_divide(const Exp& e, const detail::divides&)
- {
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_divide(e.left(), typename left_type::tag_type());
- do_multiplies(e.right(), typename right_type::tag_type());
- }
- //
- // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
- // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
- //
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
- do_divides(const Exp& e, const detail::multiply_immediates&)
- {
- using default_ops::eval_divide;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_divide(m_backend, canonical_value(e.left().value()));
- eval_divide(m_backend, canonical_value(e.right().value()));
- }
- //
- // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
- // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
- //
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
- do_divides(const Exp& e, const detail::divide_immediates&)
- {
- using default_ops::eval_divide;
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_divide(m_backend, canonical_value(e.left().value()));
- mutiply(m_backend, canonical_value(e.right().value()));
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const unknown&)
- {
- using default_ops::eval_multiply;
- boost::multiprecision::detail::maybe_promote_precision(this);
- self_type temp(e);
- eval_divide(m_backend, temp.m_backend);
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const detail::terminal&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- using default_ops::eval_modulus;
- boost::multiprecision::detail::maybe_promote_precision(this);
- eval_modulus(m_backend, canonical_value(e.value()));
- }
- template <class Exp, class Unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const Unknown&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
- using default_ops::eval_modulus;
- boost::multiprecision::detail::maybe_promote_precision(this);
- self_type temp(e);
- eval_modulus(m_backend, canonical_value(temp));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::terminal&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
- using default_ops::eval_bitwise_and;
- eval_bitwise_and(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_bitwise_and(e.left(), typename left_type::tag_type());
- do_bitwise_and(e.right(), typename right_type::tag_type());
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const unknown&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
- using default_ops::eval_bitwise_and;
- self_type temp(e);
- eval_bitwise_and(m_backend, temp.m_backend);
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::terminal&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
- using default_ops::eval_bitwise_or;
- eval_bitwise_or(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_bitwise_or(e.left(), typename left_type::tag_type());
- do_bitwise_or(e.right(), typename right_type::tag_type());
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const unknown&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
- using default_ops::eval_bitwise_or;
- self_type temp(e);
- eval_bitwise_or(m_backend, temp.m_backend);
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::terminal&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
- using default_ops::eval_bitwise_xor;
- eval_bitwise_xor(m_backend, canonical_value(e.value()));
- }
- template <class Exp>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
- using left_type = typename Exp::left_type ;
- using right_type = typename Exp::right_type;
- do_bitwise_xor(e.left(), typename left_type::tag_type());
- do_bitwise_xor(e.right(), typename right_type::tag_type());
- }
- template <class Exp, class unknown>
- BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const unknown&)
- {
- static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
- using default_ops::eval_bitwise_xor;
- self_type temp(e);
- eval_bitwise_xor(m_backend, temp.m_backend);
- }
- // Tests if the expression contains a reference to *this:
- template <class Exp>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e) const noexcept
- {
- return contains_self(e, typename Exp::arity());
- }
- template <class Exp>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
- {
- return is_realy_self(e.value());
- }
- template <class Exp>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 1> const&) const noexcept
- {
- using child_type = typename Exp::left_type;
- return contains_self(e.left(), typename child_type::arity());
- }
- template <class Exp>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 2> const&) const noexcept
- {
- using child0_type = typename Exp::left_type ;
- using child1_type = typename Exp::right_type;
- return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.right(), typename child1_type::arity());
- }
- template <class Exp>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 3> const&) const noexcept
- {
- using child0_type = typename Exp::left_type ;
- using child1_type = typename Exp::middle_type;
- using child2_type = typename Exp::right_type ;
- return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.middle(), typename child1_type::arity()) || contains_self(e.right(), typename child2_type::arity());
- }
- // Test if the expression is a reference to *this:
- template <class Exp>
- BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e) const noexcept
- {
- return is_self(e, typename Exp::arity());
- }
- template <class Exp>
- BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
- {
- return is_realy_self(e.value());
- }
- template <class Exp, int v>
- BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp&, std::integral_constant<int, v> const&) const noexcept
- {
- return false;
- }
- template <class Val>
- BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const Val&) const noexcept { return false; }
- BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const self_type& v) const noexcept { return &v == this; }
- static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const self_type& v) noexcept { return v.backend(); }
- template <class Other, expression_template_option ET2>
- static BOOST_MP_FORCEINLINE constexpr const Other& function_arg_value(const number<Other, ET2>& v) noexcept { return v.backend(); }
- template <class V>
- static BOOST_MP_FORCEINLINE constexpr const V& function_arg_value(const V& v) noexcept { return v; }
- template <class A1, class A2, class A3, class A4>
- static BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR const A1& function_arg_value(const detail::expression<detail::terminal, A1, A2, A3, A4>& exp) noexcept { return exp.value(); }
- template <class A2, class A3, class A4>
- static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const detail::expression<detail::terminal, number<Backend>, A2, A3, A4>& exp) noexcept { return exp.value().backend(); }
- Backend m_backend;
- public:
- //
- // These shouldn't really need to be public, or even member functions, but it makes implementing
- // the non-member operators way easier if they are:
- //
- static BOOST_MP_FORCEINLINE constexpr const Backend& canonical_value(const self_type& v) noexcept { return v.m_backend; }
- template <class B2, expression_template_option ET>
- static BOOST_MP_FORCEINLINE constexpr const B2& canonical_value(const number<B2, ET>& v) noexcept { return v.backend(); }
- template <class B2, expression_template_option ET>
- static BOOST_MP_FORCEINLINE constexpr B2&& canonical_value(number<B2, ET>&& v) noexcept { return static_cast<number<B2, ET>&&>(v).backend(); }
- template <class V>
- static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<!std::is_same<typename detail::canonical<V, Backend>::type, V>::value, typename detail::canonical<V, Backend>::type>::type
- canonical_value(const V& v) noexcept { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
- template <class V>
- static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<std::is_same<typename detail::canonical<V, Backend>::type, V>::value, const V&>::type
- canonical_value(const V& v) noexcept { return v; }
- static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) noexcept { return v.c_str(); }
- };
- template <class Backend, expression_template_option ExpressionTemplates>
- inline std::ostream& operator<<(std::ostream& os, const number<Backend, ExpressionTemplates>& r)
- {
- std::streamsize d = os.precision();
- std::string s = r.str(d, os.flags());
- std::streamsize ss = os.width();
- if (ss > static_cast<std::streamsize>(s.size()))
- {
- char fill = os.fill();
- if ((os.flags() & std::ios_base::left) == std::ios_base::left)
- s.append(static_cast<std::string::size_type>(ss - s.size()), fill);
- else
- s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - s.size()), fill);
- }
- return os << s;
- }
- namespace detail {
- template <class tag, class A1, class A2, class A3, class A4>
- inline std::ostream& operator<<(std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
- {
- using value_type = typename expression<tag, A1, A2, A3, A4>::result_type;
- value_type temp(r);
- return os << temp;
- }
- //
- // What follows is the input streaming code: this is not "proper" iostream code at all
- // but that's fiendishly hard to write when dealing with multiple backends all
- // with different requirements... yes we could deligate this to the backend author...
- // but we really want backends to be EASY to write!
- // For now just pull in all the characters that could possibly form the number
- // and let the backend's string parser make use of it. This fixes most use cases
- // including CSV type formats such as those used by the Random lib.
- //
- inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
- {
- std::ios_base::iostate state = std::ios_base::goodbit;
- const std::istream::sentry sentry_check(is);
- std::string result;
- if (sentry_check)
- {
- int c = is.rdbuf()->sgetc();
- for (;; c = is.rdbuf()->snextc())
- if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
- { // end of file:
- state |= std::ios_base::eofbit;
- break;
- }
- else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
- {
- // Invalid numeric character, stop reading:
- //is.rdbuf()->sputbackc(static_cast<char>(c));
- break;
- }
- else
- {
- result.append(1, std::istream::traits_type::to_char_type(c));
- }
- }
- if (!result.size())
- state |= std::ios_base::failbit;
- is.setstate(state);
- return result;
- }
- } // namespace detail
- template <class Backend, expression_template_option ExpressionTemplates>
- inline std::istream& operator>>(std::istream& is, number<Backend, ExpressionTemplates>& r)
- {
- bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
- bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
- std::string s;
- switch (boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
- {
- case boost::multiprecision::number_kind_integer:
- if (oct_format)
- s = detail::read_string_while(is, "+-01234567");
- else if (hex_format)
- s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
- else
- s = detail::read_string_while(is, "+-0123456789");
- break;
- case boost::multiprecision::number_kind_floating_point:
- s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
- break;
- default:
- is >> s;
- }
- if (s.size())
- {
- if (hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
- s.insert(s.find_first_not_of("+-"), "0x");
- if (oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
- s.insert(s.find_first_not_of("+-"), "0");
- r.assign(s);
- }
- else if (!is.fail())
- is.setstate(std::istream::failbit);
- return is;
- }
- template <class Backend, expression_template_option ExpressionTemplates>
- BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
- noexcept(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
- {
- a.swap(b);
- }
- //
- // Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
- //
- template <class Backend, expression_template_option ExpressionTemplates>
- inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
- {
- return hash_value(val.backend());
- }
- } // namespace multiprecision
- template <class T>
- class rational;
- template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
- inline std::istream& operator>>(std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
- {
- std::string s1;
- multiprecision::number<Backend, ExpressionTemplates> v1, v2;
- char c;
- bool have_hex = false;
- bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
- bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
- while ((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
- {
- if (c == 'x' || c == 'X')
- have_hex = true;
- s1.append(1, c);
- is.get();
- }
- if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
- s1.insert(static_cast<std::string::size_type>(0), "0x");
- if (oct_format && (s1[0] != '0'))
- s1.insert(static_cast<std::string::size_type>(0), "0");
- v1.assign(s1);
- s1.erase();
- if (c == '/')
- {
- is.get();
- while ((EOF != (c = static_cast<char>(is.peek()))) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
- {
- if (c == 'x' || c == 'X')
- have_hex = true;
- s1.append(1, c);
- is.get();
- }
- if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
- s1.insert(static_cast<std::string::size_type>(0), "0x");
- if (oct_format && (s1[0] != '0'))
- s1.insert(static_cast<std::string::size_type>(0), "0");
- v2.assign(s1);
- }
- else
- v2 = 1;
- r.assign(v1, v2);
- return is;
- }
- template <class T, multiprecision::expression_template_option ExpressionTemplates>
- inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
- {
- return a.numerator();
- }
- template <class T, multiprecision::expression_template_option ExpressionTemplates>
- inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
- {
- return a.denominator();
- }
- template <class T, multiprecision::expression_template_option ExpressionTemplates>
- inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const rational<multiprecision::number<T, ExpressionTemplates> >& val)
- {
- std::size_t result = hash_value(val.numerator());
- boost::hash_combine(result, hash_value(val.denominator()));
- return result;
- }
- namespace multiprecision {
- template <class I>
- struct component_type<boost::rational<I> >
- {
- using type = I;
- };
- } // namespace multiprecision
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- } // namespace boost
- namespace std {
- template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
- struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
- {
- BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val) const { return hash_value(val); }
- };
- template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
- struct hash<boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> > >
- {
- BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> >& val) const
- {
- std::size_t result = hash_value(val.numerator());
- boost::hash_combine(result, hash_value(val.denominator()));
- return result;
- }
- };
- } // namespace std
- #include <boost/multiprecision/detail/ublas_interop.hpp>
- #endif
|