number.hpp 118 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2011 John Maddock. Distributed under the Boost
  3. // Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MP_NUMBER_HPP
  6. #define BOOST_MP_NUMBER_HPP
  7. #include <cstdint>
  8. #include <boost/multiprecision/detail/standalone_config.hpp>
  9. #include <boost/multiprecision/detail/precision.hpp>
  10. #include <boost/multiprecision/detail/generic_interconvert.hpp>
  11. #include <boost/multiprecision/detail/number_compare.hpp>
  12. #include <boost/multiprecision/traits/is_restricted_conversion.hpp>
  13. #include <boost/multiprecision/traits/is_complex.hpp>
  14. #include <boost/multiprecision/traits/is_convertible_arithmetic.hpp>
  15. #include <boost/multiprecision/detail/hash.hpp>
  16. #include <boost/multiprecision/detail/number_base.hpp>
  17. #include <istream> // stream operators
  18. #include <cstdio> // EOF
  19. #include <cctype> // isspace
  20. #include <functional> // std::hash
  21. #include <type_traits>
  22. #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
  23. #include <string_view>
  24. #endif
  25. #ifndef BOOST_MP_STANDALONE
  26. #include <boost/core/nvp.hpp>
  27. #endif
  28. namespace boost {
  29. namespace multiprecision {
  30. #ifdef BOOST_MSVC
  31. // warning C4127: conditional expression is constant
  32. // warning C4714: function marked as __forceinline not inlined
  33. #pragma warning(push)
  34. #pragma warning(disable : 4127 4714 6326)
  35. #endif
  36. template <class Backend, expression_template_option ExpressionTemplates>
  37. class number
  38. {
  39. using self_type = number<Backend, ExpressionTemplates>;
  40. public:
  41. using backend_type = Backend ;
  42. using value_type = typename component_type<self_type>::type;
  43. static constexpr expression_template_option et = ExpressionTemplates;
  44. BOOST_MP_FORCEINLINE constexpr number() noexcept(noexcept(Backend())) {}
  45. BOOST_MP_FORCEINLINE constexpr number(const number& e) noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(e.m_backend) {}
  46. template <class V>
  47. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v,
  48. typename std::enable_if<
  49. (boost::multiprecision::detail::is_convertible_arithmetic<V, Backend>::value
  50. || std::is_same<std::string, V>::value
  51. || std::is_convertible<V, const char*>::value)
  52. && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value
  53. && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
  54. {
  55. m_backend = canonical_value(v);
  56. }
  57. template <class V>
  58. BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
  59. std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
  60. #ifndef BOOST_INTEL
  61. noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
  62. #endif
  63. : m_backend(canonical_value(v))
  64. {}
  65. template <class V, class U>
  66. BOOST_MP_FORCEINLINE constexpr number(const V& v, U digits10,
  67. typename std::enable_if<
  68. (boost::multiprecision::detail::is_convertible_arithmetic<V, Backend>::value
  69. || std::is_same<std::string, V>::value
  70. || std::is_convertible<V, const char*>::value)
  71. && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value
  72. && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_complex)
  73. && (boost::multiprecision::number_category<Backend>::value != boost::multiprecision::number_kind_rational)
  74. && std::is_same<self_type, value_type>::value
  75. && std::is_integral<U>::value
  76. && (std::numeric_limits<U>::digits <= std::numeric_limits<unsigned>::digits)
  77. && std::is_constructible<Backend, typename detail::canonical<V, Backend>::type const&, unsigned>::value>::type* = nullptr)
  78. : m_backend(canonical_value(v), static_cast<unsigned>(digits10))
  79. {}
  80. //
  81. // Conversions from unscoped enum's are implicit:
  82. //
  83. template <class V>
  84. BOOST_MP_FORCEINLINE
  85. #if !(defined(BOOST_MSVC) && (BOOST_MSVC <= 1900))
  86. constexpr
  87. #endif
  88. number(const V& v, typename std::enable_if<
  89. std::is_enum<V>::value && std::is_convertible<V, int>::value && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
  90. : number(static_cast<typename std::underlying_type<V>::type>(v))
  91. {}
  92. //
  93. // Conversions from scoped enum's are explicit:
  94. //
  95. template <class V>
  96. BOOST_MP_FORCEINLINE explicit
  97. #if !(defined(BOOST_MSVC) && (BOOST_MSVC <= 1900))
  98. constexpr
  99. #endif
  100. number(const V& v, typename std::enable_if<
  101. std::is_enum<V>::value && !std::is_convertible<V, int>::value && !std::is_convertible<typename detail::canonical<V, Backend>::type, Backend>::value && !detail::is_restricted_conversion<typename detail::canonical<V, Backend>::type, Backend>::value>::type* = nullptr)
  102. : number(static_cast<typename std::underlying_type<V>::type>(v))
  103. {}
  104. template <class U>
  105. BOOST_MP_FORCEINLINE constexpr number(const number& e, U digits10, typename std::enable_if<std::is_constructible<Backend, const Backend&, unsigned>::value && std::is_integral<U>::value && (std::numeric_limits<U>::digits <= std::numeric_limits<unsigned>::digits)>::type* = nullptr)
  106. noexcept(noexcept(Backend(std::declval<Backend const&>(), std::declval<unsigned>())))
  107. : m_backend(e.m_backend, static_cast<unsigned>(digits10)) {}
  108. template <class V>
  109. explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v, typename std::enable_if<
  110. (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* = nullptr)
  111. noexcept(noexcept(std::declval<Backend&>() = std::declval<typename detail::canonical<V, Backend>::type const&>()))
  112. {
  113. m_backend = canonical_value(v);
  114. }
  115. template <class V>
  116. explicit BOOST_MP_FORCEINLINE constexpr number(const V& v, typename std::enable_if<
  117. 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* = nullptr)
  118. noexcept(noexcept(Backend(std::declval<typename detail::canonical<V, Backend>::type const&>())))
  119. : m_backend(canonical_value(v)) {}
  120. template <class V>
  121. 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* = nullptr)
  122. : m_backend(canonical_value(v), digits10) {}
  123. template <expression_template_option ET>
  124. BOOST_MP_FORCEINLINE constexpr number(const number<Backend, ET>& val)
  125. noexcept(noexcept(Backend(std::declval<Backend const&>()))) : m_backend(val.backend()) {}
  126. template <class Other, expression_template_option ET>
  127. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val,
  128. typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = nullptr)
  129. noexcept(noexcept(Backend(std::declval<Other const&>())))
  130. : m_backend(val.backend()) {}
  131. template <class Other, expression_template_option ET>
  132. explicit BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
  133. (!detail::is_explicitly_convertible<Other, Backend>::value)>::type* = nullptr)
  134. {
  135. //
  136. // Attempt a generic interconvertion:
  137. //
  138. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard_1(val);
  139. detail::scoped_default_precision<number<Other, ET> > precision_guard_2(val);
  140. using detail::generic_interconvert;
  141. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  142. {
  143. if (precision_guard_1.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  144. {
  145. self_type t;
  146. generic_interconvert(t.backend(), val.backend(), number_category<Backend>(), number_category<Other>());
  147. *this = std::move(t);
  148. return;
  149. }
  150. }
  151. generic_interconvert(backend(), val.backend(), number_category<Backend>(), number_category<Other>());
  152. }
  153. template <class Other, expression_template_option ET>
  154. explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const number<Other, ET>& val, typename std::enable_if<
  155. (detail::is_explicitly_convertible<Other, Backend>::value && (detail::is_restricted_conversion<Other, Backend>::value || !std::is_convertible<Other, Backend>::value))>::type* = nullptr) noexcept(noexcept(Backend(std::declval<Other const&>())))
  156. : m_backend(val.backend()) {}
  157. template <class V, class U>
  158. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
  159. typename std::enable_if<
  160. (std::is_convertible<V, value_type>::value
  161. && std::is_convertible<U, value_type>::value
  162. && !std::is_same<value_type, self_type>::value
  163. && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
  164. && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
  165. : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)))
  166. {
  167. }
  168. template <class V, class U>
  169. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(V&& v1, const U& v2,
  170. typename std::enable_if<
  171. (std::is_convertible<V, value_type>::value
  172. && std::is_convertible<U, value_type>::value
  173. && !std::is_same<value_type, self_type>::value
  174. && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
  175. && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
  176. : m_backend(canonical_value(detail::evaluate_if_expression(static_cast<V&&>(v1))), canonical_value(detail::evaluate_if_expression(v2)))
  177. {
  178. }
  179. template <class V, class U>
  180. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, U&& v2,
  181. typename std::enable_if<
  182. (std::is_convertible<V, value_type>::value
  183. && std::is_convertible<U, value_type>::value
  184. && !std::is_same<value_type, self_type>::value
  185. && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
  186. && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
  187. : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(static_cast<U&&>(v2))))
  188. {
  189. }
  190. template <class V, class U>
  191. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(V&& v1, U&& v2,
  192. typename std::enable_if<
  193. (std::is_convertible<V, value_type>::value
  194. && std::is_convertible<U, value_type>::value
  195. && !std::is_same<value_type, self_type>::value
  196. && std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
  197. && !boost::multiprecision::detail::is_variable_precision<Backend>::value)>::type* = nullptr)
  198. : m_backend(canonical_value(detail::evaluate_if_expression(static_cast<V&&>(v1))), canonical_value(detail::evaluate_if_expression(static_cast<U&&>(v2))))
  199. {
  200. }
  201. template <class V, class U>
  202. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
  203. typename std::enable_if<
  204. (std::is_convertible<V, value_type>::value
  205. && std::is_convertible<U, value_type>::value
  206. && !std::is_same<value_type, self_type>::value
  207. && (!std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const V&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const U&>()))>::type>::type, Backend>::type const&>::value
  208. || boost::multiprecision::detail::is_variable_precision<Backend>::value))>::type* = nullptr)
  209. {
  210. using default_ops::assign_components;
  211. // Copy precision options from this type to component_type:
  212. boost::multiprecision::detail::scoped_precision_options<value_type> scoped_opts(*this);
  213. // precision guards:
  214. detail::scoped_default_precision<self_type> precision_guard(v1, v2, *this);
  215. detail::scoped_default_precision<value_type> component_precision_guard(v1, v2, *this);
  216. assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
  217. }
  218. template <class V, class U>
  219. BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2,
  220. typename std::enable_if<
  221. (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<value_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* = nullptr)
  222. {
  223. using default_ops::assign_components;
  224. // Copy precision options from this type to component_type:
  225. boost::multiprecision::detail::scoped_precision_options<value_type> scoped_opts(*this);
  226. // precision guards:
  227. detail::scoped_default_precision<self_type> precision_guard(v1, v2, *this);
  228. detail::scoped_default_precision<value_type> component_precision_guard(v1, v2, *this);
  229. assign_components(m_backend, canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)));
  230. }
  231. #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
  232. //
  233. // Support for new types in C++17
  234. //
  235. template <class Traits>
  236. explicit inline BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& view)
  237. {
  238. using default_ops::assign_from_string_view;
  239. assign_from_string_view(this->backend(), view);
  240. }
  241. template <class Traits>
  242. 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)
  243. {
  244. using default_ops::assign_from_string_view;
  245. assign_from_string_view(this->backend(), view_x, view_y);
  246. }
  247. template <class Traits>
  248. explicit BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const std::basic_string_view<char, Traits>& v, unsigned digits10)
  249. : m_backend(canonical_value(v), digits10) {}
  250. template <class Traits>
  251. BOOST_MP_CXX14_CONSTEXPR number& assign(const std::basic_string_view<char, Traits>& view)
  252. {
  253. using default_ops::assign_from_string_view;
  254. assign_from_string_view(this->backend(), view);
  255. return *this;
  256. }
  257. #endif
  258. template <class V, class U>
  259. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
  260. typename std::enable_if<(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value && !std::is_same<value_type, self_type>::value)>::type* = nullptr)
  261. : m_backend(canonical_value(detail::evaluate_if_expression(v1)), canonical_value(detail::evaluate_if_expression(v2)), digits10)
  262. {}
  263. template <class V, class U>
  264. BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR number(const V& v1, const U& v2, unsigned digits10,
  265. 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<value_type, self_type>::value) && !(std::is_convertible<V, value_type>::value && std::is_convertible<U, value_type>::value)>::type* = nullptr)
  266. : m_backend(detail::evaluate_if_expression(v1), detail::evaluate_if_expression(v2), digits10) {}
  267. template <class Other, expression_template_option ET>
  268. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(
  269. const number<Other, ET>& v1,
  270. const number<Other, ET>& v2,
  271. typename std::enable_if<
  272. std::is_convertible<Other, Backend>::value
  273. && (!std::is_constructible<Backend, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const number<Other, ET>&>()))>::type>::type, Backend>::type const&, typename detail::canonical<typename std::remove_cv<typename std::remove_reference<decltype(detail::evaluate_if_expression(std::declval<const number<Other, ET>&>()))>::type>::type, Backend>::type const&>::value || boost::multiprecision::detail::is_variable_precision<Backend>::value) >::type* = nullptr)
  274. {
  275. using default_ops::assign_components;
  276. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(v1, v2);
  277. assign_components(m_backend, v1.backend(), v2.backend());
  278. }
  279. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  280. 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)
  281. {
  282. using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
  283. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(e);
  284. //
  285. // If the current precision of *this differs from that of expression e, then we
  286. // create a temporary (which will have the correct precision thanks to precision_guard)
  287. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  288. // which causes this code to be eliminated in the common case that this type is
  289. // not actually variable precision. Pre C++17 this code should still be mostly
  290. // optimised away, but we can't prevent instantiation of the dead code leading
  291. // to longer build and possibly link times.
  292. //
  293. BOOST_IF_CONSTEXPR (std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
  294. {
  295. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  296. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  297. {
  298. number t(e);
  299. return *this = std::move(t);
  300. }
  301. }
  302. do_assign(e, tag_type());
  303. return *this;
  304. }
  305. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  306. BOOST_MP_CXX14_CONSTEXPR number& assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e)
  307. {
  308. using tag_type = std::integral_constant<bool, is_equivalent_number_type<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>;
  309. //
  310. // If the current precision of *this differs from that of expression e, then we
  311. // create a temporary (which will have the correct precision thanks to precision_guard)
  312. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  313. // which causes this code to be eliminated in the common case that this type is
  314. // not actually variable precision. Pre C++17 this code should still be mostly
  315. // optimised away, but we can't prevent instantiation of the dead code leading
  316. // to longer build and possibly link times.
  317. //
  318. BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
  319. {
  320. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  321. {
  322. const detail::scoped_default_precision<number<Backend, ExpressionTemplates>> precision_guard(e);
  323. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  324. {
  325. number t;
  326. t.assign(e);
  327. return *this = std::move(t);
  328. }
  329. }
  330. }
  331. do_assign(e, tag_type());
  332. return *this;
  333. }
  334. BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type& a, const value_type& b)
  335. {
  336. assign_components(backend(), a.backend(), b.backend());
  337. return *this;
  338. }
  339. template <class V, class U>
  340. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<(std::is_convertible<V, value_type>::value&& std::is_convertible<U, value_type>::value && !std::is_same<value_type, self_type>::value), number&>::type
  341. assign(const V& v1, const U& v2, unsigned Digits)
  342. {
  343. self_type r(v1, v2, Digits);
  344. boost::multiprecision::detail::scoped_source_precision<self_type> scope;
  345. return *this = r;
  346. }
  347. BOOST_MP_CXX14_CONSTEXPR number& assign(const value_type & a, const value_type & b, unsigned Digits)
  348. {
  349. this->precision(Digits);
  350. boost::multiprecision::detail::scoped_target_precision<self_type> scoped;
  351. assign_components(backend(), canonical_value(detail::evaluate_if_expression(a)), canonical_value(detail::evaluate_if_expression(b)));
  352. return *this;
  353. }
  354. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(const number& e)
  355. noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend const&>()))
  356. {
  357. m_backend = e.m_backend;
  358. return *this;
  359. }
  360. template <class V>
  361. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  362. operator=(const V& v)
  363. noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
  364. {
  365. m_backend = canonical_value(v);
  366. return *this;
  367. }
  368. template <class V>
  369. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v)
  370. noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
  371. {
  372. m_backend = canonical_value(v);
  373. return *this;
  374. }
  375. template <class V, class U>
  376. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number<Backend, ExpressionTemplates>& assign(const V& v, const U& digits10_or_component)
  377. noexcept(noexcept(std::declval<Backend&>() = std::declval<const typename detail::canonical<V, Backend>::type&>()))
  378. {
  379. number t(v, digits10_or_component);
  380. boost::multiprecision::detail::scoped_source_precision<self_type> scope;
  381. static_cast<void>(scope);
  382. return *this = t;
  383. }
  384. template <class Other, expression_template_option ET>
  385. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!boost::multiprecision::detail::is_explicitly_convertible<Other, Backend>::value, number<Backend, ExpressionTemplates>&>::type
  386. assign(const number<Other, ET>& v)
  387. {
  388. //
  389. // Attempt a generic interconvertion:
  390. //
  391. using detail::generic_interconvert;
  392. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
  393. detail::scoped_default_precision<number<Other, ET> > precision_guard2(*this, v);
  394. //
  395. // If the current precision of *this differs from that of value v, then we
  396. // create a temporary (which will have the correct precision thanks to precision_guard)
  397. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  398. // which causes this code to be eliminated in the common case that this type is
  399. // not actually variable precision. Pre C++17 this code should still be mostly
  400. // optimised away, but we can't prevent instantiation of the dead code leading
  401. // to longer build and possibly link times.
  402. //
  403. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  404. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  405. {
  406. number t(v);
  407. return *this = std::move(t);
  408. }
  409. generic_interconvert(backend(), v.backend(), number_category<Backend>(), number_category<Other>());
  410. return *this;
  411. }
  412. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  413. 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* = nullptr)
  414. {
  415. //
  416. // No preicsion guard here, we already have one in operator=
  417. //
  418. *this = e;
  419. }
  420. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  421. explicit BOOST_MP_CXX14_CONSTEXPR number(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e,
  422. 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* = nullptr)
  423. {
  424. //
  425. // No precision guard as assign has one already:
  426. //
  427. assign(e);
  428. }
  429. // rvalues:
  430. BOOST_MP_FORCEINLINE constexpr number(number&& r)
  431. noexcept(noexcept(Backend(std::declval<Backend>())))
  432. : m_backend(static_cast<Backend&&>(r.m_backend))
  433. {}
  434. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator=(number&& r) noexcept(noexcept(std::declval<Backend&>() = std::declval<Backend>()))
  435. {
  436. m_backend = static_cast<Backend&&>(r.m_backend);
  437. return *this;
  438. }
  439. template <class Other, expression_template_option ET>
  440. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number(number<Other, ET>&& val,
  441. typename std::enable_if<(std::is_convertible<Other, Backend>::value && !detail::is_restricted_conversion<Other, Backend>::value)>::type* = nullptr)
  442. noexcept(noexcept(Backend(std::declval<Other const&>())))
  443. : m_backend(static_cast<number<Other, ET>&&>(val).backend()) {}
  444. template <class Other, expression_template_option ET>
  445. 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
  446. operator=(number<Other, ET>&& val)
  447. noexcept(noexcept(Backend(std::declval<Other const&>())))
  448. {
  449. m_backend = std::move(val).backend();
  450. return *this;
  451. }
  452. BOOST_MP_CXX14_CONSTEXPR number& operator+=(const self_type& val)
  453. {
  454. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
  455. //
  456. // If the current precision of *this differs from that of expression e, then we
  457. // create a temporary (which will have the correct precision thanks to precision_guard)
  458. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  459. // which causes this code to be eliminated in the common case that this type is
  460. // not actually variable precision. Pre C++17 this code should still be mostly
  461. // optimised away, but we can't prevent instantiation of the dead code leading
  462. // to longer build and possibly link times.
  463. //
  464. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  465. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  466. {
  467. number t(*this + val);
  468. return *this = std::move(t);
  469. }
  470. do_add(detail::expression<detail::terminal, self_type>(val), detail::terminal());
  471. return *this;
  472. }
  473. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  474. 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)
  475. {
  476. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  477. // Create a copy if e contains this, but not if we're just doing a
  478. // x += x
  479. if ((contains_self(e) && !is_self(e)))
  480. {
  481. self_type temp(e);
  482. do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  483. }
  484. else
  485. {
  486. do_add(e, tag());
  487. }
  488. return *this;
  489. }
  490. template <class Arg1, class Arg2, class Arg3, class Arg4>
  491. BOOST_MP_CXX14_CONSTEXPR number& operator+=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
  492. {
  493. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  494. //
  495. // If the current precision of *this differs from that of expression e, then we
  496. // create a temporary (which will have the correct precision thanks to precision_guard)
  497. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  498. // which causes this code to be eliminated in the common case that this type is
  499. // not actually variable precision. Pre C++17 this code should still be mostly
  500. // optimised away, but we can't prevent instantiation of the dead code leading
  501. // to longer build and possibly link times.
  502. //
  503. BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
  504. {
  505. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  506. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  507. {
  508. number t(*this + e);
  509. return *this = std::move(t);
  510. }
  511. }
  512. //
  513. // Fused multiply-add:
  514. //
  515. using default_ops::eval_multiply_add;
  516. eval_multiply_add(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
  517. return *this;
  518. }
  519. template <class V>
  520. typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  521. BOOST_MP_CXX14_CONSTEXPR operator+=(const V& v)
  522. {
  523. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
  524. //
  525. // If the current precision of *this differs from that of value v, then we
  526. // create a temporary (which will have the correct precision thanks to precision_guard)
  527. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  528. // which causes this code to be eliminated in the common case that this type is
  529. // not actually variable precision. Pre C++17 this code should still be mostly
  530. // optimised away, but we can't prevent instantiation of the dead code leading
  531. // to longer build and possibly link times.
  532. //
  533. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  534. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  535. {
  536. number t(*this + v);
  537. return *this = std::move(t);
  538. }
  539. using default_ops::eval_add;
  540. eval_add(m_backend, canonical_value(v));
  541. return *this;
  542. }
  543. BOOST_MP_CXX14_CONSTEXPR number& operator-=(const self_type& val)
  544. {
  545. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, val);
  546. //
  547. // If the current precision of *this differs from that of expression e, then we
  548. // create a temporary (which will have the correct precision thanks to precision_guard)
  549. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  550. // which causes this code to be eliminated in the common case that this type is
  551. // not actually variable precision. Pre C++17 this code should still be mostly
  552. // optimised away, but we can't prevent instantiation of the dead code leading
  553. // to longer build and possibly link times.
  554. //
  555. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  556. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  557. {
  558. number t(*this - val);
  559. return *this = std::move(t);
  560. }
  561. do_subtract(detail::expression<detail::terminal, self_type>(val), detail::terminal());
  562. return *this;
  563. }
  564. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  565. 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)
  566. {
  567. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  568. // Create a copy if e contains this:
  569. if (contains_self(e))
  570. {
  571. self_type temp(e);
  572. do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  573. }
  574. else
  575. {
  576. do_subtract(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  577. }
  578. return *this;
  579. }
  580. template <class V>
  581. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  582. operator-=(const V& v)
  583. {
  584. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
  585. //
  586. // If the current precision of *this differs from that of value v, then we
  587. // create a temporary (which will have the correct precision thanks to precision_guard)
  588. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  589. // which causes this code to be eliminated in the common case that this type is
  590. // not actually variable precision. Pre C++17 this code should still be mostly
  591. // optimised away, but we can't prevent instantiation of the dead code leading
  592. // to longer build and possibly link times.
  593. //
  594. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  595. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  596. {
  597. number t(*this - v);
  598. return *this = std::move(t);
  599. }
  600. using default_ops::eval_subtract;
  601. eval_subtract(m_backend, canonical_value(v));
  602. return *this;
  603. }
  604. template <class Arg1, class Arg2, class Arg3, class Arg4>
  605. BOOST_MP_CXX14_CONSTEXPR number& operator-=(const detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>& e)
  606. {
  607. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  608. //
  609. // If the current precision of *this differs from that of expression e, then we
  610. // create a temporary (which will have the correct precision thanks to precision_guard)
  611. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  612. // which causes this code to be eliminated in the common case that this type is
  613. // not actually variable precision. Pre C++17 this code should still be mostly
  614. // optimised away, but we can't prevent instantiation of the dead code leading
  615. // to longer build and possibly link times.
  616. //
  617. BOOST_IF_CONSTEXPR(std::is_same<self_type, typename detail::expression<detail::multiply_immediates, Arg1, Arg2, Arg3, Arg4>::result_type>::value)
  618. {
  619. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  620. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  621. {
  622. number t(*this - e);
  623. return *this = std::move(t);
  624. }
  625. }
  626. //
  627. // Fused multiply-subtract:
  628. //
  629. using default_ops::eval_multiply_subtract;
  630. eval_multiply_subtract(m_backend, canonical_value(e.left_ref()), canonical_value(e.right_ref()));
  631. return *this;
  632. }
  633. BOOST_MP_CXX14_CONSTEXPR number& operator*=(const self_type& e)
  634. {
  635. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  636. //
  637. // If the current precision of *this differs from that of expression e, then we
  638. // create a temporary (which will have the correct precision thanks to precision_guard)
  639. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  640. // which causes this code to be eliminated in the common case that this type is
  641. // not actually variable precision. Pre C++17 this code should still be mostly
  642. // optimised away, but we can't prevent instantiation of the dead code leading
  643. // to longer build and possibly link times.
  644. //
  645. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  646. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  647. {
  648. number t(*this * e);
  649. return *this = std::move(t);
  650. }
  651. do_multiplies(detail::expression<detail::terminal, self_type>(e), detail::terminal());
  652. return *this;
  653. }
  654. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  655. 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)
  656. {
  657. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  658. // Create a temporary if the RHS references *this, but not
  659. // if we're just doing an x *= x;
  660. if ((contains_self(e) && !is_self(e)))
  661. {
  662. self_type temp(e);
  663. do_multiplies(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  664. }
  665. else
  666. {
  667. do_multiplies(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  668. }
  669. return *this;
  670. }
  671. template <class V>
  672. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  673. operator*=(const V& v)
  674. {
  675. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
  676. //
  677. // If the current precision of *this differs from that of value v, then we
  678. // create a temporary (which will have the correct precision thanks to precision_guard)
  679. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  680. // which causes this code to be eliminated in the common case that this type is
  681. // not actually variable precision. Pre C++17 this code should still be mostly
  682. // optimised away, but we can't prevent instantiation of the dead code leading
  683. // to longer build and possibly link times.
  684. //
  685. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  686. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  687. {
  688. number t(*this * v);
  689. return *this = std::move(t);
  690. }
  691. using default_ops::eval_multiply;
  692. eval_multiply(m_backend, canonical_value(v));
  693. return *this;
  694. }
  695. BOOST_MP_CXX14_CONSTEXPR number& operator%=(const self_type& e)
  696. {
  697. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  698. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  699. //
  700. // If the current precision of *this differs from that of expression e, then we
  701. // create a temporary (which will have the correct precision thanks to precision_guard)
  702. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  703. // which causes this code to be eliminated in the common case that this type is
  704. // not actually variable precision. Pre C++17 this code should still be mostly
  705. // optimised away, but we can't prevent instantiation of the dead code leading
  706. // to longer build and possibly link times.
  707. //
  708. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  709. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  710. {
  711. number t(*this % e);
  712. return *this = std::move(t);
  713. }
  714. do_modulus(detail::expression<detail::terminal, self_type>(e), detail::terminal());
  715. return *this;
  716. }
  717. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  718. 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)
  719. {
  720. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  721. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  722. // Create a temporary if the RHS references *this:
  723. if (contains_self(e))
  724. {
  725. self_type temp(e);
  726. do_modulus(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  727. }
  728. else
  729. {
  730. do_modulus(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  731. }
  732. return *this;
  733. }
  734. template <class V>
  735. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  736. operator%=(const V& v)
  737. {
  738. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  739. using default_ops::eval_modulus;
  740. eval_modulus(m_backend, canonical_value(v));
  741. return *this;
  742. }
  743. //
  744. // These operators are *not* proto-ized.
  745. // The issue is that the increment/decrement must happen
  746. // even if the result of the operator *is never used*.
  747. // Possibly we could modify our expression wrapper to
  748. // execute the increment/decrement on destruction, but
  749. // correct implementation will be tricky, so defered for now...
  750. //
  751. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator++()
  752. {
  753. using default_ops::eval_increment;
  754. eval_increment(m_backend);
  755. return *this;
  756. }
  757. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator--()
  758. {
  759. using default_ops::eval_decrement;
  760. eval_decrement(m_backend);
  761. return *this;
  762. }
  763. inline BOOST_MP_CXX14_CONSTEXPR number operator++(int)
  764. {
  765. using default_ops::eval_increment;
  766. self_type temp(*this);
  767. eval_increment(m_backend);
  768. return temp;
  769. }
  770. inline BOOST_MP_CXX14_CONSTEXPR number operator--(int)
  771. {
  772. using default_ops::eval_decrement;
  773. self_type temp(*this);
  774. eval_decrement(m_backend);
  775. return temp;
  776. }
  777. template <class V>
  778. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator<<=(V val)
  779. {
  780. static_assert(number_category<Backend>::value == number_kind_integer, "The left-shift operation is only valid for integer types");
  781. 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 > ());
  782. eval_left_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
  783. return *this;
  784. }
  785. template <class V>
  786. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<V>::value, number&>::type operator>>=(V val)
  787. {
  788. static_assert(number_category<Backend>::value == number_kind_integer, "The right-shift operation is only valid for integer types");
  789. 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>());
  790. eval_right_shift(m_backend, static_cast<std::size_t>(canonical_value(val)));
  791. return *this;
  792. }
  793. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator/=(const self_type& e)
  794. {
  795. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  796. //
  797. // If the current precision of *this differs from that of expression e, then we
  798. // create a temporary (which will have the correct precision thanks to precision_guard)
  799. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  800. // which causes this code to be eliminated in the common case that this type is
  801. // not actually variable precision. Pre C++17 this code should still be mostly
  802. // optimised away, but we can't prevent instantiation of the dead code leading
  803. // to longer build and possibly link times.
  804. //
  805. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  806. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  807. {
  808. number t(*this / e);
  809. return *this = std::move(t);
  810. }
  811. do_divide(detail::expression<detail::terminal, self_type>(e), detail::terminal());
  812. return *this;
  813. }
  814. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  815. 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)
  816. {
  817. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, e);
  818. // Create a temporary if the RHS references *this:
  819. if (contains_self(e))
  820. {
  821. self_type temp(e);
  822. do_divide(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  823. }
  824. else
  825. {
  826. do_divide(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  827. }
  828. return *this;
  829. }
  830. template <class V>
  831. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  832. operator/=(const V& v)
  833. {
  834. detail::scoped_default_precision<number<Backend, ExpressionTemplates> > precision_guard(*this, v);
  835. //
  836. // If the current precision of *this differs from that of value v, then we
  837. // create a temporary (which will have the correct precision thanks to precision_guard)
  838. // and then move the result into *this. In C++17 we add a leading "if constexpr"
  839. // which causes this code to be eliminated in the common case that this type is
  840. // not actually variable precision. Pre C++17 this code should still be mostly
  841. // optimised away, but we can't prevent instantiation of the dead code leading
  842. // to longer build and possibly link times.
  843. //
  844. BOOST_MP_CONSTEXPR_IF_VARIABLE_PRECISION(number)
  845. if (precision_guard.precision() != boost::multiprecision::detail::current_precision_of<self_type>(*this))
  846. {
  847. number t(*this / v);
  848. return *this = std::move(t);
  849. }
  850. using default_ops::eval_divide;
  851. eval_divide(m_backend, canonical_value(v));
  852. return *this;
  853. }
  854. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator&=(const self_type& e)
  855. {
  856. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  857. do_bitwise_and(detail::expression<detail::terminal, self_type>(e), detail::terminal());
  858. return *this;
  859. }
  860. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  861. 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)
  862. {
  863. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  864. // Create a temporary if the RHS references *this, but not
  865. // if we're just doing an x &= x;
  866. if (contains_self(e) && !is_self(e))
  867. {
  868. self_type temp(e);
  869. do_bitwise_and(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  870. }
  871. else
  872. {
  873. do_bitwise_and(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  874. }
  875. return *this;
  876. }
  877. template <class V>
  878. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  879. operator&=(const V& v)
  880. {
  881. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  882. using default_ops::eval_bitwise_and;
  883. eval_bitwise_and(m_backend, canonical_value(v));
  884. return *this;
  885. }
  886. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator|=(const self_type& e)
  887. {
  888. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  889. do_bitwise_or(detail::expression<detail::terminal, self_type>(e), detail::terminal());
  890. return *this;
  891. }
  892. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  893. 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)
  894. {
  895. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  896. // Create a temporary if the RHS references *this, but not
  897. // if we're just doing an x |= x;
  898. if (contains_self(e) && !is_self(e))
  899. {
  900. self_type temp(e);
  901. do_bitwise_or(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  902. }
  903. else
  904. {
  905. do_bitwise_or(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  906. }
  907. return *this;
  908. }
  909. template <class V>
  910. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  911. operator|=(const V& v)
  912. {
  913. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  914. using default_ops::eval_bitwise_or;
  915. eval_bitwise_or(m_backend, canonical_value(v));
  916. return *this;
  917. }
  918. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR number& operator^=(const self_type& e)
  919. {
  920. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  921. do_bitwise_xor(detail::expression<detail::terminal, self_type>(e), detail::terminal());
  922. return *this;
  923. }
  924. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  925. 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)
  926. {
  927. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  928. if (contains_self(e))
  929. {
  930. self_type temp(e);
  931. do_bitwise_xor(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  932. }
  933. else
  934. {
  935. do_bitwise_xor(e, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::tag_type());
  936. }
  937. return *this;
  938. }
  939. template <class V>
  940. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<V, self_type>::value, number<Backend, ExpressionTemplates>&>::type
  941. operator^=(const V& v)
  942. {
  943. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  944. using default_ops::eval_bitwise_xor;
  945. eval_bitwise_xor(m_backend, canonical_value(v));
  946. return *this;
  947. }
  948. //
  949. // swap:
  950. //
  951. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(self_type& other) noexcept(noexcept(std::declval<Backend>().swap(std::declval<Backend&>())))
  952. {
  953. m_backend.swap(other.backend());
  954. }
  955. //
  956. // Zero and sign:
  957. //
  958. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool is_zero() const
  959. {
  960. using default_ops::eval_is_zero;
  961. return eval_is_zero(m_backend);
  962. }
  963. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int sign() const
  964. {
  965. using default_ops::eval_get_sign;
  966. return eval_get_sign(m_backend);
  967. }
  968. //
  969. // String conversion functions:
  970. //
  971. std::string str(std::streamsize digits = 0, std::ios_base::fmtflags f = std::ios_base::fmtflags(0)) const
  972. {
  973. return m_backend.str(digits, f);
  974. }
  975. #ifndef BOOST_MP_STANDALONE
  976. template <class Archive>
  977. void serialize(Archive& ar, const unsigned int /*version*/)
  978. {
  979. ar& boost::make_nvp("backend", m_backend);
  980. }
  981. #endif
  982. private:
  983. template <class T>
  984. BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(T* result) const
  985. {
  986. using default_ops::eval_convert_to;
  987. eval_convert_to(result, m_backend);
  988. }
  989. template <class B2, expression_template_option ET>
  990. BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(number<B2, ET>* result) const
  991. {
  992. result->assign(*this);
  993. }
  994. BOOST_MP_CXX14_CONSTEXPR void convert_to_imp(std::string* result) const
  995. {
  996. *result = this->str();
  997. }
  998. public:
  999. template <class T>
  1000. BOOST_MP_CXX14_CONSTEXPR T convert_to() const
  1001. {
  1002. T result = T();
  1003. convert_to_imp(&result);
  1004. return result;
  1005. }
  1006. //
  1007. // Use in boolean context, and explicit conversion operators:
  1008. //
  1009. #if BOOST_WORKAROUND(BOOST_MSVC, < 1900) || (defined(__apple_build_version__) && BOOST_WORKAROUND(__clang_major__, < 9))
  1010. template <class T>
  1011. #else
  1012. template <class T, class = typename std::enable_if<std::is_enum<T>::value || !(std::is_constructible<T, detail::convertible_to<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>
  1013. #endif
  1014. explicit BOOST_MP_CXX14_CONSTEXPR operator T() const
  1015. {
  1016. return this->template convert_to<T>();
  1017. }
  1018. BOOST_MP_FORCEINLINE explicit BOOST_MP_CXX14_CONSTEXPR operator bool() const
  1019. {
  1020. return !is_zero();
  1021. }
  1022. //
  1023. // Default precision:
  1024. //
  1025. static BOOST_MP_CXX14_CONSTEXPR unsigned default_precision() noexcept
  1026. {
  1027. return Backend::default_precision();
  1028. }
  1029. static BOOST_MP_CXX14_CONSTEXPR void default_precision(unsigned digits10)
  1030. {
  1031. Backend::default_precision(digits10);
  1032. Backend::thread_default_precision(digits10);
  1033. }
  1034. static BOOST_MP_CXX14_CONSTEXPR unsigned thread_default_precision() noexcept
  1035. {
  1036. return Backend::thread_default_precision();
  1037. }
  1038. static BOOST_MP_CXX14_CONSTEXPR void thread_default_precision(unsigned digits10)
  1039. {
  1040. Backend::thread_default_precision(digits10);
  1041. }
  1042. BOOST_MP_CXX14_CONSTEXPR unsigned precision() const noexcept
  1043. {
  1044. return m_backend.precision();
  1045. }
  1046. BOOST_MP_CXX14_CONSTEXPR void precision(unsigned digits10)
  1047. {
  1048. m_backend.precision(digits10);
  1049. }
  1050. //
  1051. // Variable precision options:
  1052. //
  1053. static constexpr variable_precision_options default_variable_precision_options()noexcept
  1054. {
  1055. return Backend::default_variable_precision_options();
  1056. }
  1057. static constexpr variable_precision_options thread_default_variable_precision_options()noexcept
  1058. {
  1059. return Backend::thread_default_variable_precision_options();
  1060. }
  1061. static BOOST_MP_CXX14_CONSTEXPR void default_variable_precision_options(variable_precision_options opts)
  1062. {
  1063. Backend::default_variable_precision_options(opts);
  1064. }
  1065. static BOOST_MP_CXX14_CONSTEXPR void thread_default_variable_precision_options(variable_precision_options opts)
  1066. {
  1067. Backend::thread_default_variable_precision_options(opts);
  1068. }
  1069. //
  1070. // Comparison:
  1071. //
  1072. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int compare(const number<Backend, ExpressionTemplates>& o) const
  1073. noexcept(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
  1074. {
  1075. return m_backend.compare(o.m_backend);
  1076. }
  1077. template <class V>
  1078. 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
  1079. {
  1080. using default_ops::eval_get_sign;
  1081. if (o == 0)
  1082. return eval_get_sign(m_backend);
  1083. return m_backend.compare(canonical_value(o));
  1084. }
  1085. template <class V>
  1086. 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
  1087. {
  1088. using default_ops::eval_get_sign;
  1089. return m_backend.compare(canonical_value(o));
  1090. }
  1091. //
  1092. // Direct access to the underlying backend:
  1093. //
  1094. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() & noexcept
  1095. {
  1096. return m_backend;
  1097. }
  1098. BOOST_MP_FORCEINLINE constexpr const Backend& backend() const& noexcept { return m_backend; }
  1099. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend&& backend() && noexcept { return static_cast<Backend&&>(m_backend); }
  1100. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend const&& backend() const&& noexcept { return static_cast<Backend const&&>(m_backend); }
  1101. //
  1102. // Complex number real and imag:
  1103. //
  1104. BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
  1105. real() const
  1106. {
  1107. using default_ops::eval_real;
  1108. detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
  1109. typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
  1110. eval_real(result.backend(), backend());
  1111. return result;
  1112. }
  1113. BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
  1114. imag() const
  1115. {
  1116. using default_ops::eval_imag;
  1117. detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
  1118. typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
  1119. eval_imag(result.backend(), backend());
  1120. return result;
  1121. }
  1122. template <class T>
  1123. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value, self_type&>::type real(const T& val)
  1124. {
  1125. using default_ops::eval_set_real;
  1126. eval_set_real(backend(), canonical_value(val));
  1127. return *this;
  1128. }
  1129. template <class T>
  1130. 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)
  1131. {
  1132. using default_ops::eval_set_imag;
  1133. eval_set_imag(backend(), canonical_value(val));
  1134. return *this;
  1135. }
  1136. private:
  1137. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  1138. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
  1139. do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
  1140. {
  1141. // The result of the expression isn't the same type as this -
  1142. // create a temporary result and assign it to *this:
  1143. using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
  1144. temp_type t(e);
  1145. *this = std::move(t);
  1146. }
  1147. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  1148. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
  1149. do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
  1150. {
  1151. // The result of the expression isn't the same type as this -
  1152. // create a temporary result and assign it to *this:
  1153. using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
  1154. temp_type t(e);
  1155. this->assign(t);
  1156. }
  1157. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  1158. BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, true>&)
  1159. {
  1160. do_assign(e, tag());
  1161. }
  1162. template <class Exp>
  1163. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::add_immediates&)
  1164. {
  1165. using default_ops::eval_add;
  1166. boost::multiprecision::detail::maybe_promote_precision(this);
  1167. eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1168. }
  1169. template <class Exp>
  1170. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::subtract_immediates&)
  1171. {
  1172. using default_ops::eval_subtract;
  1173. boost::multiprecision::detail::maybe_promote_precision(this);
  1174. eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1175. }
  1176. template <class Exp>
  1177. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_immediates&)
  1178. {
  1179. using default_ops::eval_multiply;
  1180. boost::multiprecision::detail::maybe_promote_precision(this);
  1181. eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1182. }
  1183. template <class Exp>
  1184. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_add&)
  1185. {
  1186. using default_ops::eval_multiply_add;
  1187. boost::multiprecision::detail::maybe_promote_precision(this);
  1188. eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
  1189. }
  1190. template <class Exp>
  1191. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_subtract&)
  1192. {
  1193. using default_ops::eval_multiply_subtract;
  1194. boost::multiprecision::detail::maybe_promote_precision(this);
  1195. eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
  1196. }
  1197. template <class Exp>
  1198. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divide_immediates&)
  1199. {
  1200. using default_ops::eval_divide;
  1201. boost::multiprecision::detail::maybe_promote_precision(this);
  1202. eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1203. }
  1204. template <class Exp>
  1205. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::negate&)
  1206. {
  1207. using left_type = typename Exp::left_type;
  1208. do_assign(e.left(), typename left_type::tag_type());
  1209. m_backend.negate();
  1210. }
  1211. template <class Exp>
  1212. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::plus&)
  1213. {
  1214. using left_type = typename Exp::left_type ;
  1215. using right_type = typename Exp::right_type;
  1216. constexpr int const left_depth = left_type::depth;
  1217. constexpr int const right_depth = right_type::depth;
  1218. bool bl = contains_self(e.left());
  1219. bool br = contains_self(e.right());
  1220. if (bl && br)
  1221. {
  1222. self_type temp(e);
  1223. temp.m_backend.swap(this->m_backend);
  1224. }
  1225. else if (bl && is_self(e.left()))
  1226. {
  1227. // Ignore the left node, it's *this, just add the right:
  1228. do_add(e.right(), typename right_type::tag_type());
  1229. }
  1230. else if (br && is_self(e.right()))
  1231. {
  1232. // Ignore the right node, it's *this, just add the left:
  1233. do_add(e.left(), typename left_type::tag_type());
  1234. }
  1235. else if (!br && (bl || (left_depth >= right_depth)))
  1236. { // br is always false, but if bl is true we must take the this branch:
  1237. do_assign(e.left(), typename left_type::tag_type());
  1238. do_add(e.right(), typename right_type::tag_type());
  1239. }
  1240. else
  1241. {
  1242. do_assign(e.right(), typename right_type::tag_type());
  1243. do_add(e.left(), typename left_type::tag_type());
  1244. }
  1245. }
  1246. template <class Exp>
  1247. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::minus&)
  1248. {
  1249. using left_type = typename Exp::left_type ;
  1250. using right_type = typename Exp::right_type;
  1251. constexpr int const left_depth = left_type::depth;
  1252. constexpr int const right_depth = right_type::depth;
  1253. bool bl = contains_self(e.left());
  1254. bool br = contains_self(e.right());
  1255. if (bl && br)
  1256. {
  1257. self_type temp(e);
  1258. temp.m_backend.swap(this->m_backend);
  1259. }
  1260. else if (bl && is_self(e.left()))
  1261. {
  1262. // Ignore the left node, it's *this, just subtract the right:
  1263. do_subtract(e.right(), typename right_type::tag_type());
  1264. }
  1265. else if (br && is_self(e.right()))
  1266. {
  1267. // Ignore the right node, it's *this, just subtract the left and negate the result:
  1268. do_subtract(e.left(), typename left_type::tag_type());
  1269. m_backend.negate();
  1270. }
  1271. else if (!br && (bl || (left_depth >= right_depth)))
  1272. { // br is always false, but if bl is true we must take the this branch:
  1273. do_assign(e.left(), typename left_type::tag_type());
  1274. do_subtract(e.right(), typename right_type::tag_type());
  1275. }
  1276. else
  1277. {
  1278. do_assign(e.right(), typename right_type::tag_type());
  1279. do_subtract(e.left(), typename left_type::tag_type());
  1280. m_backend.negate();
  1281. }
  1282. }
  1283. template <class Exp>
  1284. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiplies&)
  1285. {
  1286. using left_type = typename Exp::left_type ;
  1287. using right_type = typename Exp::right_type;
  1288. constexpr int const left_depth = left_type::depth;
  1289. constexpr int const right_depth = right_type::depth;
  1290. bool bl = contains_self(e.left());
  1291. bool br = contains_self(e.right());
  1292. if (bl && br)
  1293. {
  1294. self_type temp(e);
  1295. temp.m_backend.swap(this->m_backend);
  1296. }
  1297. else if (bl && is_self(e.left()))
  1298. {
  1299. // Ignore the left node, it's *this, just add the right:
  1300. do_multiplies(e.right(), typename right_type::tag_type());
  1301. }
  1302. else if (br && is_self(e.right()))
  1303. {
  1304. // Ignore the right node, it's *this, just add the left:
  1305. do_multiplies(e.left(), typename left_type::tag_type());
  1306. }
  1307. else if (!br && (bl || (left_depth >= right_depth)))
  1308. { // br is always false, but if bl is true we must take the this branch:
  1309. do_assign(e.left(), typename left_type::tag_type());
  1310. do_multiplies(e.right(), typename right_type::tag_type());
  1311. }
  1312. else
  1313. {
  1314. do_assign(e.right(), typename right_type::tag_type());
  1315. do_multiplies(e.left(), typename left_type::tag_type());
  1316. }
  1317. }
  1318. template <class Exp>
  1319. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divides&)
  1320. {
  1321. using left_type = typename Exp::left_type ;
  1322. using right_type = typename Exp::right_type;
  1323. bool bl = contains_self(e.left());
  1324. bool br = contains_self(e.right());
  1325. if (bl && is_self(e.left()))
  1326. {
  1327. // Ignore the left node, it's *this, just add the right:
  1328. do_divide(e.right(), typename right_type::tag_type());
  1329. }
  1330. else if (br)
  1331. {
  1332. self_type temp(e);
  1333. temp.m_backend.swap(this->m_backend);
  1334. }
  1335. else
  1336. {
  1337. do_assign(e.left(), typename left_type::tag_type());
  1338. do_divide(e.right(), typename right_type::tag_type());
  1339. }
  1340. }
  1341. template <class Exp>
  1342. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus&)
  1343. {
  1344. //
  1345. // This operation is only valid for integer backends:
  1346. //
  1347. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1348. using left_type = typename Exp::left_type ;
  1349. using right_type = typename Exp::right_type;
  1350. bool bl = contains_self(e.left());
  1351. bool br = contains_self(e.right());
  1352. if (bl && is_self(e.left()))
  1353. {
  1354. // Ignore the left node, it's *this, just add the right:
  1355. do_modulus(e.right(), typename right_type::tag_type());
  1356. }
  1357. else if (br)
  1358. {
  1359. self_type temp(e);
  1360. temp.m_backend.swap(this->m_backend);
  1361. }
  1362. else
  1363. {
  1364. do_assign(e.left(), typename left_type::tag_type());
  1365. do_modulus(e.right(), typename right_type::tag_type());
  1366. }
  1367. }
  1368. template <class Exp>
  1369. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus_immediates&)
  1370. {
  1371. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1372. using default_ops::eval_modulus;
  1373. boost::multiprecision::detail::maybe_promote_precision(this);
  1374. eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1375. }
  1376. template <class Exp>
  1377. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and&)
  1378. {
  1379. //
  1380. // This operation is only valid for integer backends:
  1381. //
  1382. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1383. using left_type = typename Exp::left_type ;
  1384. using right_type = typename Exp::right_type;
  1385. constexpr int const left_depth = left_type::depth;
  1386. constexpr int const right_depth = right_type::depth;
  1387. bool bl = contains_self(e.left());
  1388. bool br = contains_self(e.right());
  1389. if (bl && is_self(e.left()))
  1390. {
  1391. // Ignore the left node, it's *this, just add the right:
  1392. do_bitwise_and(e.right(), typename right_type::tag_type());
  1393. }
  1394. else if (br && is_self(e.right()))
  1395. {
  1396. do_bitwise_and(e.left(), typename left_type::tag_type());
  1397. }
  1398. else if (!br && (bl || (left_depth >= right_depth)))
  1399. {
  1400. do_assign(e.left(), typename left_type::tag_type());
  1401. do_bitwise_and(e.right(), typename right_type::tag_type());
  1402. }
  1403. else
  1404. {
  1405. do_assign(e.right(), typename right_type::tag_type());
  1406. do_bitwise_and(e.left(), typename left_type::tag_type());
  1407. }
  1408. }
  1409. template <class Exp>
  1410. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
  1411. {
  1412. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1413. using default_ops::eval_bitwise_and;
  1414. eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1415. }
  1416. template <class Exp>
  1417. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or&)
  1418. {
  1419. //
  1420. // This operation is only valid for integer backends:
  1421. //
  1422. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1423. using left_type = typename Exp::left_type ;
  1424. using right_type = typename Exp::right_type;
  1425. constexpr int const left_depth = left_type::depth;
  1426. constexpr int const right_depth = right_type::depth;
  1427. bool bl = contains_self(e.left());
  1428. bool br = contains_self(e.right());
  1429. if (bl && is_self(e.left()))
  1430. {
  1431. // Ignore the left node, it's *this, just add the right:
  1432. do_bitwise_or(e.right(), typename right_type::tag_type());
  1433. }
  1434. else if (br && is_self(e.right()))
  1435. {
  1436. do_bitwise_or(e.left(), typename left_type::tag_type());
  1437. }
  1438. else if (!br && (bl || (left_depth >= right_depth)))
  1439. {
  1440. do_assign(e.left(), typename left_type::tag_type());
  1441. do_bitwise_or(e.right(), typename right_type::tag_type());
  1442. }
  1443. else
  1444. {
  1445. do_assign(e.right(), typename right_type::tag_type());
  1446. do_bitwise_or(e.left(), typename left_type::tag_type());
  1447. }
  1448. }
  1449. template <class Exp>
  1450. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
  1451. {
  1452. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1453. using default_ops::eval_bitwise_or;
  1454. eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1455. }
  1456. template <class Exp>
  1457. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor&)
  1458. {
  1459. //
  1460. // This operation is only valid for integer backends:
  1461. //
  1462. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1463. using left_type = typename Exp::left_type ;
  1464. using right_type = typename Exp::right_type;
  1465. constexpr int const left_depth = left_type::depth;
  1466. constexpr int const right_depth = right_type::depth;
  1467. bool bl = contains_self(e.left());
  1468. bool br = contains_self(e.right());
  1469. if (bl && is_self(e.left()))
  1470. {
  1471. // Ignore the left node, it's *this, just add the right:
  1472. do_bitwise_xor(e.right(), typename right_type::tag_type());
  1473. }
  1474. else if (br && is_self(e.right()))
  1475. {
  1476. do_bitwise_xor(e.left(), typename left_type::tag_type());
  1477. }
  1478. else if (!br && (bl || (left_depth >= right_depth)))
  1479. {
  1480. do_assign(e.left(), typename left_type::tag_type());
  1481. do_bitwise_xor(e.right(), typename right_type::tag_type());
  1482. }
  1483. else
  1484. {
  1485. do_assign(e.right(), typename right_type::tag_type());
  1486. do_bitwise_xor(e.left(), typename left_type::tag_type());
  1487. }
  1488. }
  1489. template <class Exp>
  1490. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
  1491. {
  1492. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1493. using default_ops::eval_bitwise_xor;
  1494. eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1495. }
  1496. template <class Exp>
  1497. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::terminal&)
  1498. {
  1499. if (!is_self(e))
  1500. {
  1501. m_backend = canonical_value(e.value());
  1502. }
  1503. }
  1504. template <class Exp>
  1505. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::function&)
  1506. {
  1507. using tag_type = typename Exp::arity;
  1508. boost::multiprecision::detail::maybe_promote_precision(this);
  1509. do_assign_function(e, tag_type());
  1510. }
  1511. template <class Exp>
  1512. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_left&)
  1513. {
  1514. // We can only shift by an integer value, not an arbitrary expression:
  1515. using left_type = typename Exp::left_type ;
  1516. using right_type = typename Exp::right_type ;
  1517. using right_arity = typename right_type::arity;
  1518. static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
  1519. using right_value_type = typename right_type::result_type;
  1520. static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
  1521. using tag_type = typename left_type::tag_type;
  1522. do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
  1523. }
  1524. template <class Exp>
  1525. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_right&)
  1526. {
  1527. // We can only shift by an integer value, not an arbitrary expression:
  1528. using left_type = typename Exp::left_type ;
  1529. using right_type = typename Exp::right_type ;
  1530. using right_arity = typename right_type::arity;
  1531. static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
  1532. using right_value_type = typename right_type::result_type;
  1533. static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
  1534. using tag_type = typename left_type::tag_type;
  1535. do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
  1536. }
  1537. template <class Exp>
  1538. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_complement&)
  1539. {
  1540. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
  1541. using default_ops::eval_complement;
  1542. self_type temp(e.left());
  1543. eval_complement(m_backend, temp.backend());
  1544. }
  1545. template <class Exp>
  1546. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::complement_immediates&)
  1547. {
  1548. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
  1549. using default_ops::eval_complement;
  1550. eval_complement(m_backend, canonical_value(e.left().value()));
  1551. }
  1552. template <class Exp, class Val>
  1553. BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
  1554. {
  1555. static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
  1556. using default_ops::eval_right_shift;
  1557. 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>());
  1558. eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
  1559. }
  1560. template <class Exp, class Val>
  1561. BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
  1562. {
  1563. static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
  1564. using default_ops::eval_left_shift;
  1565. 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>());
  1566. eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
  1567. }
  1568. template <class Exp, class Val, class Tag>
  1569. BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
  1570. {
  1571. static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
  1572. using default_ops::eval_right_shift;
  1573. self_type temp(e);
  1574. 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>());
  1575. eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
  1576. }
  1577. template <class Exp, class Val, class Tag>
  1578. BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
  1579. {
  1580. static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
  1581. using default_ops::eval_left_shift;
  1582. self_type temp(e);
  1583. 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>());
  1584. eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
  1585. }
  1586. template <class Exp>
  1587. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 1>&)
  1588. {
  1589. e.left().value()(&m_backend);
  1590. }
  1591. template <class Exp>
  1592. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 2>&)
  1593. {
  1594. using right_type = typename Exp::right_type ;
  1595. using tag_type = typename right_type::tag_type;
  1596. do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
  1597. }
  1598. template <class F, class Exp>
  1599. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
  1600. {
  1601. f(m_backend, function_arg_value(val));
  1602. }
  1603. template <class F, class Exp, class Tag>
  1604. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const Tag&)
  1605. {
  1606. typename Exp::result_type t(val);
  1607. f(m_backend, t.backend());
  1608. }
  1609. template <class Exp>
  1610. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 3>&)
  1611. {
  1612. using middle_type = typename Exp::middle_type ;
  1613. using tag_type = typename middle_type::tag_type;
  1614. using end_type = typename Exp::right_type ;
  1615. using end_tag = typename end_type::tag_type ;
  1616. do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
  1617. }
  1618. template <class F, class Exp1, class Exp2>
  1619. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
  1620. {
  1621. f(m_backend, function_arg_value(val1), function_arg_value(val2));
  1622. }
  1623. template <class F, class Exp1, class Exp2, class Tag1>
  1624. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
  1625. {
  1626. typename Exp1::result_type temp1(val1);
  1627. f(m_backend, std::move(temp1.backend()), function_arg_value(val2));
  1628. }
  1629. template <class F, class Exp1, class Exp2, class Tag2>
  1630. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
  1631. {
  1632. typename Exp2::result_type temp2(val2);
  1633. f(m_backend, function_arg_value(val1), std::move(temp2.backend()));
  1634. }
  1635. template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
  1636. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
  1637. {
  1638. typename Exp1::result_type temp1(val1);
  1639. typename Exp2::result_type temp2(val2);
  1640. f(m_backend, std::move(temp1.backend()), std::move(temp2.backend()));
  1641. }
  1642. template <class Exp>
  1643. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 4>&)
  1644. {
  1645. using left_type = typename Exp::left_middle_type ;
  1646. using left_tag_type = typename left_type::tag_type ;
  1647. using middle_type = typename Exp::right_middle_type;
  1648. using middle_tag_type = typename middle_type::tag_type ;
  1649. using right_type = typename Exp::right_type ;
  1650. using right_tag_type = typename right_type::tag_type ;
  1651. 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());
  1652. }
  1653. template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
  1654. 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)
  1655. {
  1656. do_assign_function_3b(f, val1, val2, val3, t2, t3);
  1657. }
  1658. template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
  1659. 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)
  1660. {
  1661. typename Exp1::result_type t(val1);
  1662. do_assign_function_3b(f, std::move(t), val2, val3, t2, t3);
  1663. }
  1664. template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
  1665. 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)
  1666. {
  1667. do_assign_function_3c(f, val1, val2, val3, t3);
  1668. }
  1669. template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
  1670. 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)
  1671. {
  1672. typename Exp2::result_type t(val2);
  1673. do_assign_function_3c(f, val1, std::move(t), val3, t3);
  1674. }
  1675. template <class F, class Exp1, class Exp2, class Exp3>
  1676. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
  1677. {
  1678. f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
  1679. }
  1680. template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
  1681. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
  1682. {
  1683. typename Exp3::result_type t(val3);
  1684. do_assign_function_3c(f, val1, val2, std::move(t), detail::terminal());
  1685. }
  1686. template <class Exp>
  1687. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::terminal&)
  1688. {
  1689. using default_ops::eval_add;
  1690. boost::multiprecision::detail::maybe_promote_precision(this);
  1691. eval_add(m_backend, canonical_value(e.value()));
  1692. }
  1693. template <class Exp>
  1694. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::negate&)
  1695. {
  1696. using left_type = typename Exp::left_type;
  1697. boost::multiprecision::detail::maybe_promote_precision(this);
  1698. do_subtract(e.left(), typename left_type::tag_type());
  1699. }
  1700. template <class Exp>
  1701. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::plus&)
  1702. {
  1703. using left_type = typename Exp::left_type ;
  1704. using right_type = typename Exp::right_type;
  1705. do_add(e.left(), typename left_type::tag_type());
  1706. do_add(e.right(), typename right_type::tag_type());
  1707. }
  1708. template <class Exp>
  1709. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::minus&)
  1710. {
  1711. using left_type = typename Exp::left_type ;
  1712. using right_type = typename Exp::right_type;
  1713. do_add(e.left(), typename left_type::tag_type());
  1714. do_subtract(e.right(), typename right_type::tag_type());
  1715. }
  1716. template <class Exp, class unknown>
  1717. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const unknown&)
  1718. {
  1719. self_type temp(e);
  1720. do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  1721. }
  1722. template <class Exp>
  1723. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::add_immediates&)
  1724. {
  1725. using default_ops::eval_add;
  1726. boost::multiprecision::detail::maybe_promote_precision(this);
  1727. eval_add(m_backend, canonical_value(e.left().value()));
  1728. eval_add(m_backend, canonical_value(e.right().value()));
  1729. }
  1730. template <class Exp>
  1731. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::subtract_immediates&)
  1732. {
  1733. using default_ops::eval_add;
  1734. using default_ops::eval_subtract;
  1735. boost::multiprecision::detail::maybe_promote_precision(this);
  1736. eval_add(m_backend, canonical_value(e.left().value()));
  1737. eval_subtract(m_backend, canonical_value(e.right().value()));
  1738. }
  1739. template <class Exp>
  1740. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::terminal&)
  1741. {
  1742. using default_ops::eval_subtract;
  1743. boost::multiprecision::detail::maybe_promote_precision(this);
  1744. eval_subtract(m_backend, canonical_value(e.value()));
  1745. }
  1746. template <class Exp>
  1747. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::negate&)
  1748. {
  1749. using left_type = typename Exp::left_type;
  1750. do_add(e.left(), typename left_type::tag_type());
  1751. }
  1752. template <class Exp>
  1753. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::plus&)
  1754. {
  1755. using left_type = typename Exp::left_type ;
  1756. using right_type = typename Exp::right_type;
  1757. do_subtract(e.left(), typename left_type::tag_type());
  1758. do_subtract(e.right(), typename right_type::tag_type());
  1759. }
  1760. template <class Exp>
  1761. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::minus&)
  1762. {
  1763. using left_type = typename Exp::left_type ;
  1764. using right_type = typename Exp::right_type;
  1765. do_subtract(e.left(), typename left_type::tag_type());
  1766. do_add(e.right(), typename right_type::tag_type());
  1767. }
  1768. template <class Exp>
  1769. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::add_immediates&)
  1770. {
  1771. using default_ops::eval_subtract;
  1772. boost::multiprecision::detail::maybe_promote_precision(this);
  1773. eval_subtract(m_backend, canonical_value(e.left().value()));
  1774. eval_subtract(m_backend, canonical_value(e.right().value()));
  1775. }
  1776. template <class Exp>
  1777. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::subtract_immediates&)
  1778. {
  1779. using default_ops::eval_add;
  1780. using default_ops::eval_subtract;
  1781. eval_subtract(m_backend, canonical_value(e.left().value()));
  1782. eval_add(m_backend, canonical_value(e.right().value()));
  1783. }
  1784. template <class Exp, class unknown>
  1785. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const unknown&)
  1786. {
  1787. self_type temp(e);
  1788. do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  1789. }
  1790. template <class Exp>
  1791. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::terminal&)
  1792. {
  1793. using default_ops::eval_multiply;
  1794. boost::multiprecision::detail::maybe_promote_precision(this);
  1795. eval_multiply(m_backend, canonical_value(e.value()));
  1796. }
  1797. template <class Exp>
  1798. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::negate&)
  1799. {
  1800. using left_type = typename Exp::left_type;
  1801. do_multiplies(e.left(), typename left_type::tag_type());
  1802. m_backend.negate();
  1803. }
  1804. template <class Exp>
  1805. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiplies&)
  1806. {
  1807. using left_type = typename Exp::left_type ;
  1808. using right_type = typename Exp::right_type;
  1809. do_multiplies(e.left(), typename left_type::tag_type());
  1810. do_multiplies(e.right(), typename right_type::tag_type());
  1811. }
  1812. //
  1813. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1814. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1815. //
  1816. template <class Exp>
  1817. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1818. do_multiplies(const Exp& e, const detail::divides&)
  1819. {
  1820. using left_type = typename Exp::left_type ;
  1821. using right_type = typename Exp::right_type;
  1822. do_multiplies(e.left(), typename left_type::tag_type());
  1823. do_divide(e.right(), typename right_type::tag_type());
  1824. }
  1825. template <class Exp>
  1826. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiply_immediates&)
  1827. {
  1828. using default_ops::eval_multiply;
  1829. boost::multiprecision::detail::maybe_promote_precision(this);
  1830. eval_multiply(m_backend, canonical_value(e.left().value()));
  1831. eval_multiply(m_backend, canonical_value(e.right().value()));
  1832. }
  1833. //
  1834. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1835. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1836. //
  1837. template <class Exp>
  1838. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1839. do_multiplies(const Exp& e, const detail::divide_immediates&)
  1840. {
  1841. using default_ops::eval_divide;
  1842. using default_ops::eval_multiply;
  1843. boost::multiprecision::detail::maybe_promote_precision(this);
  1844. eval_multiply(m_backend, canonical_value(e.left().value()));
  1845. eval_divide(m_backend, canonical_value(e.right().value()));
  1846. }
  1847. template <class Exp, class unknown>
  1848. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const unknown&)
  1849. {
  1850. using default_ops::eval_multiply;
  1851. boost::multiprecision::detail::maybe_promote_precision(this);
  1852. self_type temp(e);
  1853. eval_multiply(m_backend, temp.m_backend);
  1854. }
  1855. template <class Exp>
  1856. BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::terminal&)
  1857. {
  1858. using default_ops::eval_divide;
  1859. boost::multiprecision::detail::maybe_promote_precision(this);
  1860. eval_divide(m_backend, canonical_value(e.value()));
  1861. }
  1862. template <class Exp>
  1863. BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::negate&)
  1864. {
  1865. using left_type = typename Exp::left_type;
  1866. do_divide(e.left(), typename left_type::tag_type());
  1867. m_backend.negate();
  1868. }
  1869. //
  1870. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1871. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1872. //
  1873. template <class Exp>
  1874. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1875. do_divide(const Exp& e, const detail::multiplies&)
  1876. {
  1877. using left_type = typename Exp::left_type ;
  1878. using right_type = typename Exp::right_type;
  1879. do_divide(e.left(), typename left_type::tag_type());
  1880. do_divide(e.right(), typename right_type::tag_type());
  1881. }
  1882. //
  1883. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1884. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1885. //
  1886. template <class Exp>
  1887. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1888. do_divide(const Exp& e, const detail::divides&)
  1889. {
  1890. using left_type = typename Exp::left_type ;
  1891. using right_type = typename Exp::right_type;
  1892. do_divide(e.left(), typename left_type::tag_type());
  1893. do_multiplies(e.right(), typename right_type::tag_type());
  1894. }
  1895. //
  1896. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1897. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1898. //
  1899. template <class Exp>
  1900. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1901. do_divides(const Exp& e, const detail::multiply_immediates&)
  1902. {
  1903. using default_ops::eval_divide;
  1904. boost::multiprecision::detail::maybe_promote_precision(this);
  1905. eval_divide(m_backend, canonical_value(e.left().value()));
  1906. eval_divide(m_backend, canonical_value(e.right().value()));
  1907. }
  1908. //
  1909. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1910. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1911. //
  1912. template <class Exp>
  1913. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1914. do_divides(const Exp& e, const detail::divide_immediates&)
  1915. {
  1916. using default_ops::eval_divide;
  1917. using default_ops::eval_multiply;
  1918. boost::multiprecision::detail::maybe_promote_precision(this);
  1919. eval_divide(m_backend, canonical_value(e.left().value()));
  1920. mutiply(m_backend, canonical_value(e.right().value()));
  1921. }
  1922. template <class Exp, class unknown>
  1923. BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const unknown&)
  1924. {
  1925. using default_ops::eval_multiply;
  1926. boost::multiprecision::detail::maybe_promote_precision(this);
  1927. self_type temp(e);
  1928. eval_divide(m_backend, temp.m_backend);
  1929. }
  1930. template <class Exp>
  1931. BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const detail::terminal&)
  1932. {
  1933. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1934. using default_ops::eval_modulus;
  1935. boost::multiprecision::detail::maybe_promote_precision(this);
  1936. eval_modulus(m_backend, canonical_value(e.value()));
  1937. }
  1938. template <class Exp, class Unknown>
  1939. BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const Unknown&)
  1940. {
  1941. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1942. using default_ops::eval_modulus;
  1943. boost::multiprecision::detail::maybe_promote_precision(this);
  1944. self_type temp(e);
  1945. eval_modulus(m_backend, canonical_value(temp));
  1946. }
  1947. template <class Exp>
  1948. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::terminal&)
  1949. {
  1950. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  1951. using default_ops::eval_bitwise_and;
  1952. eval_bitwise_and(m_backend, canonical_value(e.value()));
  1953. }
  1954. template <class Exp>
  1955. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
  1956. {
  1957. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  1958. using left_type = typename Exp::left_type ;
  1959. using right_type = typename Exp::right_type;
  1960. do_bitwise_and(e.left(), typename left_type::tag_type());
  1961. do_bitwise_and(e.right(), typename right_type::tag_type());
  1962. }
  1963. template <class Exp, class unknown>
  1964. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const unknown&)
  1965. {
  1966. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  1967. using default_ops::eval_bitwise_and;
  1968. self_type temp(e);
  1969. eval_bitwise_and(m_backend, temp.m_backend);
  1970. }
  1971. template <class Exp>
  1972. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::terminal&)
  1973. {
  1974. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  1975. using default_ops::eval_bitwise_or;
  1976. eval_bitwise_or(m_backend, canonical_value(e.value()));
  1977. }
  1978. template <class Exp>
  1979. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
  1980. {
  1981. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  1982. using left_type = typename Exp::left_type ;
  1983. using right_type = typename Exp::right_type;
  1984. do_bitwise_or(e.left(), typename left_type::tag_type());
  1985. do_bitwise_or(e.right(), typename right_type::tag_type());
  1986. }
  1987. template <class Exp, class unknown>
  1988. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const unknown&)
  1989. {
  1990. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  1991. using default_ops::eval_bitwise_or;
  1992. self_type temp(e);
  1993. eval_bitwise_or(m_backend, temp.m_backend);
  1994. }
  1995. template <class Exp>
  1996. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::terminal&)
  1997. {
  1998. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  1999. using default_ops::eval_bitwise_xor;
  2000. eval_bitwise_xor(m_backend, canonical_value(e.value()));
  2001. }
  2002. template <class Exp>
  2003. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
  2004. {
  2005. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  2006. using left_type = typename Exp::left_type ;
  2007. using right_type = typename Exp::right_type;
  2008. do_bitwise_xor(e.left(), typename left_type::tag_type());
  2009. do_bitwise_xor(e.right(), typename right_type::tag_type());
  2010. }
  2011. template <class Exp, class unknown>
  2012. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const unknown&)
  2013. {
  2014. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  2015. using default_ops::eval_bitwise_xor;
  2016. self_type temp(e);
  2017. eval_bitwise_xor(m_backend, temp.m_backend);
  2018. }
  2019. // Tests if the expression contains a reference to *this:
  2020. template <class Exp>
  2021. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e) const noexcept
  2022. {
  2023. return contains_self(e, typename Exp::arity());
  2024. }
  2025. template <class Exp>
  2026. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
  2027. {
  2028. return is_realy_self(e.value());
  2029. }
  2030. template <class Exp>
  2031. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 1> const&) const noexcept
  2032. {
  2033. using child_type = typename Exp::left_type;
  2034. return contains_self(e.left(), typename child_type::arity());
  2035. }
  2036. template <class Exp>
  2037. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 2> const&) const noexcept
  2038. {
  2039. using child0_type = typename Exp::left_type ;
  2040. using child1_type = typename Exp::right_type;
  2041. return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.right(), typename child1_type::arity());
  2042. }
  2043. template <class Exp>
  2044. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 3> const&) const noexcept
  2045. {
  2046. using child0_type = typename Exp::left_type ;
  2047. using child1_type = typename Exp::middle_type;
  2048. using child2_type = typename Exp::right_type ;
  2049. 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());
  2050. }
  2051. template <class Exp>
  2052. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 4> const&) const noexcept
  2053. {
  2054. using child0_type = typename Exp::left_type;
  2055. using child1_type = typename Exp::left_middle_type;
  2056. using child2_type = typename Exp::right_middle_type;
  2057. using child3_type = typename Exp::right_type;
  2058. return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.left_middle(), typename child1_type::arity()) || contains_self(e.right_middle(), typename child2_type::arity()) || contains_self(e.right(), typename child3_type::arity());
  2059. }
  2060. // Test if the expression is a reference to *this:
  2061. template <class Exp>
  2062. BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e) const noexcept
  2063. {
  2064. return is_self(e, typename Exp::arity());
  2065. }
  2066. template <class Exp>
  2067. BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
  2068. {
  2069. return is_realy_self(e.value());
  2070. }
  2071. template <class Exp, int v>
  2072. BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp&, std::integral_constant<int, v> const&) const noexcept
  2073. {
  2074. return false;
  2075. }
  2076. template <class Val>
  2077. BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const Val&) const noexcept { return false; }
  2078. BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const self_type& v) const noexcept { return &v == this; }
  2079. static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const self_type& v) noexcept { return v.backend(); }
  2080. template <class Other, expression_template_option ET2>
  2081. static BOOST_MP_FORCEINLINE constexpr const Other& function_arg_value(const number<Other, ET2>& v) noexcept { return v.backend(); }
  2082. template <class V>
  2083. static BOOST_MP_FORCEINLINE constexpr const V& function_arg_value(const V& v) noexcept { return v; }
  2084. template <class A1, class A2, class A3, class A4>
  2085. 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(); }
  2086. template <class A2, class A3, class A4>
  2087. 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(); }
  2088. Backend m_backend;
  2089. public:
  2090. //
  2091. // These shouldn't really need to be public, or even member functions, but it makes implementing
  2092. // the non-member operators way easier if they are:
  2093. //
  2094. static BOOST_MP_FORCEINLINE constexpr const Backend& canonical_value(const self_type& v) noexcept { return v.m_backend; }
  2095. template <class B2, expression_template_option ET>
  2096. static BOOST_MP_FORCEINLINE constexpr const B2& canonical_value(const number<B2, ET>& v) noexcept { return v.backend(); }
  2097. template <class B2, expression_template_option ET>
  2098. static BOOST_MP_FORCEINLINE constexpr B2&& canonical_value(number<B2, ET>&& v) noexcept { return static_cast<number<B2, ET>&&>(v).backend(); }
  2099. template <class V>
  2100. 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
  2101. canonical_value(const V& v) noexcept { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
  2102. template <class V>
  2103. static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<std::is_same<typename detail::canonical<V, Backend>::type, V>::value, const V&>::type
  2104. canonical_value(const V& v) noexcept { return v; }
  2105. static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) noexcept { return v.c_str(); }
  2106. };
  2107. template <class Backend, expression_template_option ExpressionTemplates>
  2108. inline std::ostream& operator<<(std::ostream& os, const number<Backend, ExpressionTemplates>& r)
  2109. {
  2110. std::streamsize d = os.precision();
  2111. std::string s = r.str(d, os.flags());
  2112. std::streamsize ss = os.width();
  2113. if (ss > static_cast<std::streamsize>(s.size()))
  2114. {
  2115. char fill = os.fill();
  2116. if ((os.flags() & std::ios_base::left) == std::ios_base::left)
  2117. s.append(static_cast<std::string::size_type>(ss - static_cast<std::streamsize>(s.size())), fill);
  2118. else
  2119. s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - static_cast<std::streamsize>(s.size())), fill);
  2120. }
  2121. return os << s;
  2122. }
  2123. template <class Backend, expression_template_option ExpressionTemplates>
  2124. std::string to_string(const number<Backend, ExpressionTemplates>& val)
  2125. {
  2126. return val.str(6, std::ios_base::fixed|std::ios_base::showpoint);
  2127. }
  2128. namespace detail {
  2129. template <class tag, class A1, class A2, class A3, class A4>
  2130. inline std::ostream& operator<<(std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
  2131. {
  2132. using value_type = typename expression<tag, A1, A2, A3, A4>::result_type;
  2133. value_type temp(r);
  2134. return os << temp;
  2135. }
  2136. //
  2137. // What follows is the input streaming code: this is not "proper" iostream code at all
  2138. // but that's fiendishly hard to write when dealing with multiple backends all
  2139. // with different requirements... yes we could deligate this to the backend author...
  2140. // but we really want backends to be EASY to write!
  2141. // For now just pull in all the characters that could possibly form the number
  2142. // and let the backend's string parser make use of it. This fixes most use cases
  2143. // including CSV type formats such as those used by the Random lib.
  2144. //
  2145. inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
  2146. {
  2147. std::ios_base::iostate state = std::ios_base::goodbit;
  2148. const std::istream::sentry sentry_check(is);
  2149. std::string result;
  2150. if (sentry_check)
  2151. {
  2152. int c = is.rdbuf()->sgetc();
  2153. for (;; c = is.rdbuf()->snextc())
  2154. if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
  2155. { // end of file:
  2156. state |= std::ios_base::eofbit;
  2157. break;
  2158. }
  2159. else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
  2160. {
  2161. // Invalid numeric character, stop reading:
  2162. //is.rdbuf()->sputbackc(static_cast<char>(c));
  2163. break;
  2164. }
  2165. else
  2166. {
  2167. result.append(1, std::istream::traits_type::to_char_type(c));
  2168. }
  2169. }
  2170. if (!result.size())
  2171. state |= std::ios_base::failbit;
  2172. is.setstate(state);
  2173. return result;
  2174. }
  2175. } // namespace detail
  2176. template <class Backend, expression_template_option ExpressionTemplates>
  2177. inline std::istream& operator>>(std::istream& is, number<Backend, ExpressionTemplates>& r)
  2178. {
  2179. bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
  2180. bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
  2181. std::string s;
  2182. switch (boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
  2183. {
  2184. case boost::multiprecision::number_kind_integer:
  2185. if (oct_format)
  2186. s = detail::read_string_while(is, "+-01234567");
  2187. else if (hex_format)
  2188. s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
  2189. else
  2190. s = detail::read_string_while(is, "+-0123456789");
  2191. break;
  2192. case boost::multiprecision::number_kind_rational:
  2193. if (oct_format)
  2194. s = detail::read_string_while(is, "+-01234567/");
  2195. else if (hex_format)
  2196. s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789/");
  2197. else
  2198. s = detail::read_string_while(is, "+-0123456789/");
  2199. break;
  2200. case boost::multiprecision::number_kind_floating_point:
  2201. BOOST_IF_CONSTEXPR(std::is_same<number<Backend, ExpressionTemplates>, typename number<Backend, ExpressionTemplates>::value_type>::value)
  2202. s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
  2203. else
  2204. // Interval:
  2205. s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY{,}");
  2206. break;
  2207. case boost::multiprecision::number_kind_complex:
  2208. s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY,()");
  2209. break;
  2210. default:
  2211. is >> s;
  2212. }
  2213. if (s.size())
  2214. {
  2215. if (hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
  2216. s.insert(s.find_first_not_of("+-"), "0x");
  2217. if (oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
  2218. s.insert(s.find_first_not_of("+-"), "0");
  2219. r.assign(s);
  2220. }
  2221. else if (!is.fail())
  2222. is.setstate(std::istream::failbit);
  2223. return is;
  2224. }
  2225. template <class Backend, expression_template_option ExpressionTemplates>
  2226. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
  2227. noexcept(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
  2228. {
  2229. a.swap(b);
  2230. }
  2231. //
  2232. // Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
  2233. //
  2234. template <class Backend, expression_template_option ExpressionTemplates>
  2235. inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
  2236. {
  2237. return hash_value(val.backend());
  2238. }
  2239. namespace detail {
  2240. BOOST_MP_FORCEINLINE bool istream_peek(std::istream& is, char& c, bool have_hex)
  2241. {
  2242. int i = is.peek();
  2243. c = static_cast<char>(i);
  2244. return (EOF != i) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')));
  2245. }
  2246. } // namespace detail
  2247. } // namespace multiprecision
  2248. template <class T>
  2249. class rational;
  2250. template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
  2251. inline std::istream& operator>>(std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
  2252. {
  2253. std::string s1;
  2254. multiprecision::number<Backend, ExpressionTemplates> v1, v2;
  2255. char c;
  2256. bool have_hex = false;
  2257. bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
  2258. bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
  2259. while (multiprecision::detail::istream_peek(is, c, have_hex))
  2260. {
  2261. if (c == 'x' || c == 'X')
  2262. have_hex = true;
  2263. s1.append(1, c);
  2264. is.get();
  2265. }
  2266. if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
  2267. s1.insert(static_cast<std::string::size_type>(0), "0x");
  2268. if (oct_format && (s1[0] != '0'))
  2269. s1.insert(static_cast<std::string::size_type>(0), "0");
  2270. v1.assign(s1);
  2271. s1.erase();
  2272. if (c == '/')
  2273. {
  2274. is.get();
  2275. while (multiprecision::detail::istream_peek(is, c, have_hex))
  2276. {
  2277. if (c == 'x' || c == 'X')
  2278. have_hex = true;
  2279. s1.append(1, c);
  2280. is.get();
  2281. }
  2282. if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
  2283. s1.insert(static_cast<std::string::size_type>(0), "0x");
  2284. if (oct_format && (s1[0] != '0'))
  2285. s1.insert(static_cast<std::string::size_type>(0), "0");
  2286. v2.assign(s1);
  2287. }
  2288. else
  2289. v2 = 1;
  2290. r.assign(v1, v2);
  2291. return is;
  2292. }
  2293. template <class T, multiprecision::expression_template_option ExpressionTemplates>
  2294. inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
  2295. {
  2296. return a.numerator();
  2297. }
  2298. template <class T, multiprecision::expression_template_option ExpressionTemplates>
  2299. inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
  2300. {
  2301. return a.denominator();
  2302. }
  2303. template <class T, multiprecision::expression_template_option ExpressionTemplates>
  2304. inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const rational<multiprecision::number<T, ExpressionTemplates> >& val)
  2305. {
  2306. std::size_t result = hash_value(val.numerator());
  2307. boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
  2308. return result;
  2309. }
  2310. namespace multiprecision {
  2311. template <class I>
  2312. struct component_type<boost::rational<I> >
  2313. {
  2314. using type = I;
  2315. };
  2316. } // namespace multiprecision
  2317. #ifdef BOOST_MSVC
  2318. #pragma warning(pop)
  2319. #endif
  2320. } // namespace boost
  2321. namespace std {
  2322. template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
  2323. struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
  2324. {
  2325. BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val) const { return hash_value(val); }
  2326. };
  2327. template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
  2328. struct hash<boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> > >
  2329. {
  2330. BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> >& val) const
  2331. {
  2332. std::size_t result = hash_value(val.numerator());
  2333. boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
  2334. return result;
  2335. }
  2336. };
  2337. } // namespace std
  2338. #include <boost/multiprecision/detail/ublas_interop.hpp>
  2339. #endif