number.hpp 118 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500
  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. Backend::thread_default_variable_precision_options(opts);
  1065. }
  1066. static BOOST_MP_CXX14_CONSTEXPR void thread_default_variable_precision_options(variable_precision_options opts)
  1067. {
  1068. Backend::thread_default_variable_precision_options(opts);
  1069. }
  1070. //
  1071. // Comparison:
  1072. //
  1073. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR int compare(const number<Backend, ExpressionTemplates>& o) const
  1074. noexcept(noexcept(std::declval<Backend>().compare(std::declval<Backend>())))
  1075. {
  1076. return m_backend.compare(o.m_backend);
  1077. }
  1078. template <class V>
  1079. 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
  1080. {
  1081. using default_ops::eval_get_sign;
  1082. if (o == 0)
  1083. return eval_get_sign(m_backend);
  1084. return m_backend.compare(canonical_value(o));
  1085. }
  1086. template <class V>
  1087. 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
  1088. {
  1089. using default_ops::eval_get_sign;
  1090. return m_backend.compare(canonical_value(o));
  1091. }
  1092. //
  1093. // Direct access to the underlying backend:
  1094. //
  1095. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend& backend() & noexcept
  1096. {
  1097. return m_backend;
  1098. }
  1099. BOOST_MP_FORCEINLINE constexpr const Backend& backend() const& noexcept { return m_backend; }
  1100. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend&& backend() && noexcept { return static_cast<Backend&&>(m_backend); }
  1101. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR Backend const&& backend() const&& noexcept { return static_cast<Backend const&&>(m_backend); }
  1102. //
  1103. // Complex number real and imag:
  1104. //
  1105. BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
  1106. real() const
  1107. {
  1108. using default_ops::eval_real;
  1109. detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
  1110. typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
  1111. eval_real(result.backend(), backend());
  1112. return result;
  1113. }
  1114. BOOST_MP_CXX14_CONSTEXPR typename scalar_result_from_possible_complex<number<Backend, ExpressionTemplates> >::type
  1115. imag() const
  1116. {
  1117. using default_ops::eval_imag;
  1118. detail::scoped_default_precision<typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type> precision_guard(*this);
  1119. typename scalar_result_from_possible_complex<multiprecision::number<Backend, ExpressionTemplates> >::type result;
  1120. eval_imag(result.backend(), backend());
  1121. return result;
  1122. }
  1123. template <class T>
  1124. inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T, self_type>::value, self_type&>::type real(const T& val)
  1125. {
  1126. using default_ops::eval_set_real;
  1127. eval_set_real(backend(), canonical_value(val));
  1128. return *this;
  1129. }
  1130. template <class T>
  1131. 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)
  1132. {
  1133. using default_ops::eval_set_imag;
  1134. eval_set_imag(backend(), canonical_value(val));
  1135. return *this;
  1136. }
  1137. private:
  1138. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  1139. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
  1140. do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
  1141. {
  1142. // The result of the expression isn't the same type as this -
  1143. // create a temporary result and assign it to *this:
  1144. using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
  1145. temp_type t(e);
  1146. *this = std::move(t);
  1147. }
  1148. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  1149. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!std::is_assignable<number, typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value>::type
  1150. do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, false>&)
  1151. {
  1152. // The result of the expression isn't the same type as this -
  1153. // create a temporary result and assign it to *this:
  1154. using temp_type = typename detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type;
  1155. temp_type t(e);
  1156. this->assign(t);
  1157. }
  1158. template <class tag, class Arg1, class Arg2, class Arg3, class Arg4>
  1159. BOOST_MP_CXX14_CONSTEXPR void do_assign(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& e, const std::integral_constant<bool, true>&)
  1160. {
  1161. do_assign(e, tag());
  1162. }
  1163. template <class Exp>
  1164. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::add_immediates&)
  1165. {
  1166. using default_ops::eval_add;
  1167. boost::multiprecision::detail::maybe_promote_precision(this);
  1168. eval_add(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1169. }
  1170. template <class Exp>
  1171. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::subtract_immediates&)
  1172. {
  1173. using default_ops::eval_subtract;
  1174. boost::multiprecision::detail::maybe_promote_precision(this);
  1175. eval_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1176. }
  1177. template <class Exp>
  1178. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_immediates&)
  1179. {
  1180. using default_ops::eval_multiply;
  1181. boost::multiprecision::detail::maybe_promote_precision(this);
  1182. eval_multiply(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1183. }
  1184. template <class Exp>
  1185. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_add&)
  1186. {
  1187. using default_ops::eval_multiply_add;
  1188. boost::multiprecision::detail::maybe_promote_precision(this);
  1189. eval_multiply_add(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
  1190. }
  1191. template <class Exp>
  1192. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiply_subtract&)
  1193. {
  1194. using default_ops::eval_multiply_subtract;
  1195. boost::multiprecision::detail::maybe_promote_precision(this);
  1196. eval_multiply_subtract(m_backend, canonical_value(e.left().value()), canonical_value(e.middle().value()), canonical_value(e.right().value()));
  1197. }
  1198. template <class Exp>
  1199. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divide_immediates&)
  1200. {
  1201. using default_ops::eval_divide;
  1202. boost::multiprecision::detail::maybe_promote_precision(this);
  1203. eval_divide(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1204. }
  1205. template <class Exp>
  1206. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::negate&)
  1207. {
  1208. using left_type = typename Exp::left_type;
  1209. do_assign(e.left(), typename left_type::tag_type());
  1210. m_backend.negate();
  1211. }
  1212. template <class Exp>
  1213. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::plus&)
  1214. {
  1215. using left_type = typename Exp::left_type ;
  1216. using right_type = typename Exp::right_type;
  1217. constexpr int const left_depth = left_type::depth;
  1218. constexpr int const right_depth = right_type::depth;
  1219. bool bl = contains_self(e.left());
  1220. bool br = contains_self(e.right());
  1221. if (bl && br)
  1222. {
  1223. self_type temp(e);
  1224. temp.m_backend.swap(this->m_backend);
  1225. }
  1226. else if (bl && is_self(e.left()))
  1227. {
  1228. // Ignore the left node, it's *this, just add the right:
  1229. do_add(e.right(), typename right_type::tag_type());
  1230. }
  1231. else if (br && is_self(e.right()))
  1232. {
  1233. // Ignore the right node, it's *this, just add the left:
  1234. do_add(e.left(), typename left_type::tag_type());
  1235. }
  1236. else if (!br && (bl || (left_depth >= right_depth)))
  1237. { // br is always false, but if bl is true we must take the this branch:
  1238. do_assign(e.left(), typename left_type::tag_type());
  1239. do_add(e.right(), typename right_type::tag_type());
  1240. }
  1241. else
  1242. {
  1243. do_assign(e.right(), typename right_type::tag_type());
  1244. do_add(e.left(), typename left_type::tag_type());
  1245. }
  1246. }
  1247. template <class Exp>
  1248. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::minus&)
  1249. {
  1250. using left_type = typename Exp::left_type ;
  1251. using right_type = typename Exp::right_type;
  1252. constexpr int const left_depth = left_type::depth;
  1253. constexpr int const right_depth = right_type::depth;
  1254. bool bl = contains_self(e.left());
  1255. bool br = contains_self(e.right());
  1256. if (bl && br)
  1257. {
  1258. self_type temp(e);
  1259. temp.m_backend.swap(this->m_backend);
  1260. }
  1261. else if (bl && is_self(e.left()))
  1262. {
  1263. // Ignore the left node, it's *this, just subtract the right:
  1264. do_subtract(e.right(), typename right_type::tag_type());
  1265. }
  1266. else if (br && is_self(e.right()))
  1267. {
  1268. // Ignore the right node, it's *this, just subtract the left and negate the result:
  1269. do_subtract(e.left(), typename left_type::tag_type());
  1270. m_backend.negate();
  1271. }
  1272. else if (!br && (bl || (left_depth >= right_depth)))
  1273. { // br is always false, but if bl is true we must take the this branch:
  1274. do_assign(e.left(), typename left_type::tag_type());
  1275. do_subtract(e.right(), typename right_type::tag_type());
  1276. }
  1277. else
  1278. {
  1279. do_assign(e.right(), typename right_type::tag_type());
  1280. do_subtract(e.left(), typename left_type::tag_type());
  1281. m_backend.negate();
  1282. }
  1283. }
  1284. template <class Exp>
  1285. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::multiplies&)
  1286. {
  1287. using left_type = typename Exp::left_type ;
  1288. using right_type = typename Exp::right_type;
  1289. constexpr int const left_depth = left_type::depth;
  1290. constexpr int const right_depth = right_type::depth;
  1291. bool bl = contains_self(e.left());
  1292. bool br = contains_self(e.right());
  1293. if (bl && br)
  1294. {
  1295. self_type temp(e);
  1296. temp.m_backend.swap(this->m_backend);
  1297. }
  1298. else if (bl && is_self(e.left()))
  1299. {
  1300. // Ignore the left node, it's *this, just add the right:
  1301. do_multiplies(e.right(), typename right_type::tag_type());
  1302. }
  1303. else if (br && is_self(e.right()))
  1304. {
  1305. // Ignore the right node, it's *this, just add the left:
  1306. do_multiplies(e.left(), typename left_type::tag_type());
  1307. }
  1308. else if (!br && (bl || (left_depth >= right_depth)))
  1309. { // br is always false, but if bl is true we must take the this branch:
  1310. do_assign(e.left(), typename left_type::tag_type());
  1311. do_multiplies(e.right(), typename right_type::tag_type());
  1312. }
  1313. else
  1314. {
  1315. do_assign(e.right(), typename right_type::tag_type());
  1316. do_multiplies(e.left(), typename left_type::tag_type());
  1317. }
  1318. }
  1319. template <class Exp>
  1320. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::divides&)
  1321. {
  1322. using left_type = typename Exp::left_type ;
  1323. using right_type = typename Exp::right_type;
  1324. bool bl = contains_self(e.left());
  1325. bool br = contains_self(e.right());
  1326. if (bl && is_self(e.left()))
  1327. {
  1328. // Ignore the left node, it's *this, just add the right:
  1329. do_divide(e.right(), typename right_type::tag_type());
  1330. }
  1331. else if (br)
  1332. {
  1333. self_type temp(e);
  1334. temp.m_backend.swap(this->m_backend);
  1335. }
  1336. else
  1337. {
  1338. do_assign(e.left(), typename left_type::tag_type());
  1339. do_divide(e.right(), typename right_type::tag_type());
  1340. }
  1341. }
  1342. template <class Exp>
  1343. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus&)
  1344. {
  1345. //
  1346. // This operation is only valid for integer backends:
  1347. //
  1348. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1349. using left_type = typename Exp::left_type ;
  1350. using right_type = typename Exp::right_type;
  1351. bool bl = contains_self(e.left());
  1352. bool br = contains_self(e.right());
  1353. if (bl && is_self(e.left()))
  1354. {
  1355. // Ignore the left node, it's *this, just add the right:
  1356. do_modulus(e.right(), typename right_type::tag_type());
  1357. }
  1358. else if (br)
  1359. {
  1360. self_type temp(e);
  1361. temp.m_backend.swap(this->m_backend);
  1362. }
  1363. else
  1364. {
  1365. do_assign(e.left(), typename left_type::tag_type());
  1366. do_modulus(e.right(), typename right_type::tag_type());
  1367. }
  1368. }
  1369. template <class Exp>
  1370. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::modulus_immediates&)
  1371. {
  1372. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1373. using default_ops::eval_modulus;
  1374. boost::multiprecision::detail::maybe_promote_precision(this);
  1375. eval_modulus(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1376. }
  1377. template <class Exp>
  1378. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and&)
  1379. {
  1380. //
  1381. // This operation is only valid for integer backends:
  1382. //
  1383. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1384. using left_type = typename Exp::left_type ;
  1385. using right_type = typename Exp::right_type;
  1386. constexpr int const left_depth = left_type::depth;
  1387. constexpr int const right_depth = right_type::depth;
  1388. bool bl = contains_self(e.left());
  1389. bool br = contains_self(e.right());
  1390. if (bl && is_self(e.left()))
  1391. {
  1392. // Ignore the left node, it's *this, just add the right:
  1393. do_bitwise_and(e.right(), typename right_type::tag_type());
  1394. }
  1395. else if (br && is_self(e.right()))
  1396. {
  1397. do_bitwise_and(e.left(), typename left_type::tag_type());
  1398. }
  1399. else if (!br && (bl || (left_depth >= right_depth)))
  1400. {
  1401. do_assign(e.left(), typename left_type::tag_type());
  1402. do_bitwise_and(e.right(), typename right_type::tag_type());
  1403. }
  1404. else
  1405. {
  1406. do_assign(e.right(), typename right_type::tag_type());
  1407. do_bitwise_and(e.left(), typename left_type::tag_type());
  1408. }
  1409. }
  1410. template <class Exp>
  1411. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_and_immediates&)
  1412. {
  1413. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1414. using default_ops::eval_bitwise_and;
  1415. eval_bitwise_and(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1416. }
  1417. template <class Exp>
  1418. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or&)
  1419. {
  1420. //
  1421. // This operation is only valid for integer backends:
  1422. //
  1423. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1424. using left_type = typename Exp::left_type ;
  1425. using right_type = typename Exp::right_type;
  1426. constexpr int const left_depth = left_type::depth;
  1427. constexpr int const right_depth = right_type::depth;
  1428. bool bl = contains_self(e.left());
  1429. bool br = contains_self(e.right());
  1430. if (bl && is_self(e.left()))
  1431. {
  1432. // Ignore the left node, it's *this, just add the right:
  1433. do_bitwise_or(e.right(), typename right_type::tag_type());
  1434. }
  1435. else if (br && is_self(e.right()))
  1436. {
  1437. do_bitwise_or(e.left(), typename left_type::tag_type());
  1438. }
  1439. else if (!br && (bl || (left_depth >= right_depth)))
  1440. {
  1441. do_assign(e.left(), typename left_type::tag_type());
  1442. do_bitwise_or(e.right(), typename right_type::tag_type());
  1443. }
  1444. else
  1445. {
  1446. do_assign(e.right(), typename right_type::tag_type());
  1447. do_bitwise_or(e.left(), typename left_type::tag_type());
  1448. }
  1449. }
  1450. template <class Exp>
  1451. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_or_immediates&)
  1452. {
  1453. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1454. using default_ops::eval_bitwise_or;
  1455. eval_bitwise_or(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1456. }
  1457. template <class Exp>
  1458. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor&)
  1459. {
  1460. //
  1461. // This operation is only valid for integer backends:
  1462. //
  1463. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1464. using left_type = typename Exp::left_type ;
  1465. using right_type = typename Exp::right_type;
  1466. constexpr int const left_depth = left_type::depth;
  1467. constexpr int const right_depth = right_type::depth;
  1468. bool bl = contains_self(e.left());
  1469. bool br = contains_self(e.right());
  1470. if (bl && is_self(e.left()))
  1471. {
  1472. // Ignore the left node, it's *this, just add the right:
  1473. do_bitwise_xor(e.right(), typename right_type::tag_type());
  1474. }
  1475. else if (br && is_self(e.right()))
  1476. {
  1477. do_bitwise_xor(e.left(), typename left_type::tag_type());
  1478. }
  1479. else if (!br && (bl || (left_depth >= right_depth)))
  1480. {
  1481. do_assign(e.left(), typename left_type::tag_type());
  1482. do_bitwise_xor(e.right(), typename right_type::tag_type());
  1483. }
  1484. else
  1485. {
  1486. do_assign(e.right(), typename right_type::tag_type());
  1487. do_bitwise_xor(e.left(), typename left_type::tag_type());
  1488. }
  1489. }
  1490. template <class Exp>
  1491. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_xor_immediates&)
  1492. {
  1493. static_assert(number_category<Backend>::value == number_kind_integer, "Bitwise operations are only valid for integer types");
  1494. using default_ops::eval_bitwise_xor;
  1495. eval_bitwise_xor(m_backend, canonical_value(e.left().value()), canonical_value(e.right().value()));
  1496. }
  1497. template <class Exp>
  1498. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::terminal&)
  1499. {
  1500. if (!is_self(e))
  1501. {
  1502. m_backend = canonical_value(e.value());
  1503. }
  1504. }
  1505. template <class Exp>
  1506. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::function&)
  1507. {
  1508. using tag_type = typename Exp::arity;
  1509. boost::multiprecision::detail::maybe_promote_precision(this);
  1510. do_assign_function(e, tag_type());
  1511. }
  1512. template <class Exp>
  1513. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_left&)
  1514. {
  1515. // We can only shift by an integer value, not an arbitrary expression:
  1516. using left_type = typename Exp::left_type ;
  1517. using right_type = typename Exp::right_type ;
  1518. using right_arity = typename right_type::arity;
  1519. static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
  1520. using right_value_type = typename right_type::result_type;
  1521. static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
  1522. using tag_type = typename left_type::tag_type;
  1523. do_assign_left_shift(e.left(), canonical_value(e.right().value()), tag_type());
  1524. }
  1525. template <class Exp>
  1526. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::shift_right&)
  1527. {
  1528. // We can only shift by an integer value, not an arbitrary expression:
  1529. using left_type = typename Exp::left_type ;
  1530. using right_type = typename Exp::right_type ;
  1531. using right_arity = typename right_type::arity;
  1532. static_assert(right_arity::value == 0, "The left shift operator requires an integer value for the shift operand.");
  1533. using right_value_type = typename right_type::result_type;
  1534. static_assert(boost::multiprecision::detail::is_integral<right_value_type>::value, "The left shift operator requires an integer value for the shift operand.");
  1535. using tag_type = typename left_type::tag_type;
  1536. do_assign_right_shift(e.left(), canonical_value(e.right().value()), tag_type());
  1537. }
  1538. template <class Exp>
  1539. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::bitwise_complement&)
  1540. {
  1541. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
  1542. using default_ops::eval_complement;
  1543. self_type temp(e.left());
  1544. eval_complement(m_backend, temp.backend());
  1545. }
  1546. template <class Exp>
  1547. BOOST_MP_CXX14_CONSTEXPR void do_assign(const Exp& e, const detail::complement_immediates&)
  1548. {
  1549. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ~ operation is only valid for integer types");
  1550. using default_ops::eval_complement;
  1551. eval_complement(m_backend, canonical_value(e.left().value()));
  1552. }
  1553. template <class Exp, class Val>
  1554. BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const detail::terminal&)
  1555. {
  1556. static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
  1557. using default_ops::eval_right_shift;
  1558. 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>());
  1559. eval_right_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
  1560. }
  1561. template <class Exp, class Val>
  1562. BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const detail::terminal&)
  1563. {
  1564. static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
  1565. using default_ops::eval_left_shift;
  1566. 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>());
  1567. eval_left_shift(m_backend, canonical_value(e.value()), static_cast<std::size_t>(val));
  1568. }
  1569. template <class Exp, class Val, class Tag>
  1570. BOOST_MP_CXX14_CONSTEXPR void do_assign_right_shift(const Exp& e, const Val& val, const Tag&)
  1571. {
  1572. static_assert(number_category<Backend>::value == number_kind_integer, "The right shift operation is only valid for integer types");
  1573. using default_ops::eval_right_shift;
  1574. self_type temp(e);
  1575. 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>());
  1576. eval_right_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
  1577. }
  1578. template <class Exp, class Val, class Tag>
  1579. BOOST_MP_CXX14_CONSTEXPR void do_assign_left_shift(const Exp& e, const Val& val, const Tag&)
  1580. {
  1581. static_assert(number_category<Backend>::value == number_kind_integer, "The left shift operation is only valid for integer types");
  1582. using default_ops::eval_left_shift;
  1583. self_type temp(e);
  1584. 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>());
  1585. eval_left_shift(m_backend, temp.backend(), static_cast<std::size_t>(val));
  1586. }
  1587. template <class Exp>
  1588. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 1>&)
  1589. {
  1590. e.left().value()(&m_backend);
  1591. }
  1592. template <class Exp>
  1593. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 2>&)
  1594. {
  1595. using right_type = typename Exp::right_type ;
  1596. using tag_type = typename right_type::tag_type;
  1597. do_assign_function_1(e.left().value(), e.right_ref(), tag_type());
  1598. }
  1599. template <class F, class Exp>
  1600. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const detail::terminal&)
  1601. {
  1602. f(m_backend, function_arg_value(val));
  1603. }
  1604. template <class F, class Exp, class Tag>
  1605. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_1(const F& f, const Exp& val, const Tag&)
  1606. {
  1607. typename Exp::result_type t(val);
  1608. f(m_backend, t.backend());
  1609. }
  1610. template <class Exp>
  1611. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 3>&)
  1612. {
  1613. using middle_type = typename Exp::middle_type ;
  1614. using tag_type = typename middle_type::tag_type;
  1615. using end_type = typename Exp::right_type ;
  1616. using end_tag = typename end_type::tag_type ;
  1617. do_assign_function_2(e.left().value(), e.middle_ref(), e.right_ref(), tag_type(), end_tag());
  1618. }
  1619. template <class F, class Exp1, class Exp2>
  1620. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const detail::terminal&)
  1621. {
  1622. f(m_backend, function_arg_value(val1), function_arg_value(val2));
  1623. }
  1624. template <class F, class Exp1, class Exp2, class Tag1>
  1625. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const detail::terminal&)
  1626. {
  1627. typename Exp1::result_type temp1(val1);
  1628. f(m_backend, std::move(temp1.backend()), function_arg_value(val2));
  1629. }
  1630. template <class F, class Exp1, class Exp2, class Tag2>
  1631. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const detail::terminal&, const Tag2&)
  1632. {
  1633. typename Exp2::result_type temp2(val2);
  1634. f(m_backend, function_arg_value(val1), std::move(temp2.backend()));
  1635. }
  1636. template <class F, class Exp1, class Exp2, class Tag1, class Tag2>
  1637. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_2(const F& f, const Exp1& val1, const Exp2& val2, const Tag1&, const Tag2&)
  1638. {
  1639. typename Exp1::result_type temp1(val1);
  1640. typename Exp2::result_type temp2(val2);
  1641. f(m_backend, std::move(temp1.backend()), std::move(temp2.backend()));
  1642. }
  1643. template <class Exp>
  1644. BOOST_MP_CXX14_CONSTEXPR void do_assign_function(const Exp& e, const std::integral_constant<int, 4>&)
  1645. {
  1646. using left_type = typename Exp::left_middle_type ;
  1647. using left_tag_type = typename left_type::tag_type ;
  1648. using middle_type = typename Exp::right_middle_type;
  1649. using middle_tag_type = typename middle_type::tag_type ;
  1650. using right_type = typename Exp::right_type ;
  1651. using right_tag_type = typename right_type::tag_type ;
  1652. 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());
  1653. }
  1654. template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
  1655. 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)
  1656. {
  1657. do_assign_function_3b(f, val1, val2, val3, t2, t3);
  1658. }
  1659. template <class F, class Exp1, class Exp2, class Exp3, class Tag1, class Tag2, class Tag3>
  1660. 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)
  1661. {
  1662. typename Exp1::result_type t(val1);
  1663. do_assign_function_3b(f, std::move(t), val2, val3, t2, t3);
  1664. }
  1665. template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
  1666. 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)
  1667. {
  1668. do_assign_function_3c(f, val1, val2, val3, t3);
  1669. }
  1670. template <class F, class Exp1, class Exp2, class Exp3, class Tag2, class Tag3>
  1671. 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)
  1672. {
  1673. typename Exp2::result_type t(val2);
  1674. do_assign_function_3c(f, val1, std::move(t), val3, t3);
  1675. }
  1676. template <class F, class Exp1, class Exp2, class Exp3>
  1677. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const detail::terminal&)
  1678. {
  1679. f(m_backend, function_arg_value(val1), function_arg_value(val2), function_arg_value(val3));
  1680. }
  1681. template <class F, class Exp1, class Exp2, class Exp3, class Tag3>
  1682. BOOST_MP_CXX14_CONSTEXPR void do_assign_function_3c(const F& f, const Exp1& val1, const Exp2& val2, const Exp3& val3, const Tag3& /*t3*/)
  1683. {
  1684. typename Exp3::result_type t(val3);
  1685. do_assign_function_3c(f, val1, val2, std::move(t), detail::terminal());
  1686. }
  1687. template <class Exp>
  1688. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::terminal&)
  1689. {
  1690. using default_ops::eval_add;
  1691. boost::multiprecision::detail::maybe_promote_precision(this);
  1692. eval_add(m_backend, canonical_value(e.value()));
  1693. }
  1694. template <class Exp>
  1695. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::negate&)
  1696. {
  1697. using left_type = typename Exp::left_type;
  1698. boost::multiprecision::detail::maybe_promote_precision(this);
  1699. do_subtract(e.left(), typename left_type::tag_type());
  1700. }
  1701. template <class Exp>
  1702. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::plus&)
  1703. {
  1704. using left_type = typename Exp::left_type ;
  1705. using right_type = typename Exp::right_type;
  1706. do_add(e.left(), typename left_type::tag_type());
  1707. do_add(e.right(), typename right_type::tag_type());
  1708. }
  1709. template <class Exp>
  1710. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::minus&)
  1711. {
  1712. using left_type = typename Exp::left_type ;
  1713. using right_type = typename Exp::right_type;
  1714. do_add(e.left(), typename left_type::tag_type());
  1715. do_subtract(e.right(), typename right_type::tag_type());
  1716. }
  1717. template <class Exp, class unknown>
  1718. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const unknown&)
  1719. {
  1720. self_type temp(e);
  1721. do_add(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  1722. }
  1723. template <class Exp>
  1724. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::add_immediates&)
  1725. {
  1726. using default_ops::eval_add;
  1727. boost::multiprecision::detail::maybe_promote_precision(this);
  1728. eval_add(m_backend, canonical_value(e.left().value()));
  1729. eval_add(m_backend, canonical_value(e.right().value()));
  1730. }
  1731. template <class Exp>
  1732. BOOST_MP_CXX14_CONSTEXPR void do_add(const Exp& e, const detail::subtract_immediates&)
  1733. {
  1734. using default_ops::eval_add;
  1735. using default_ops::eval_subtract;
  1736. boost::multiprecision::detail::maybe_promote_precision(this);
  1737. eval_add(m_backend, canonical_value(e.left().value()));
  1738. eval_subtract(m_backend, canonical_value(e.right().value()));
  1739. }
  1740. template <class Exp>
  1741. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::terminal&)
  1742. {
  1743. using default_ops::eval_subtract;
  1744. boost::multiprecision::detail::maybe_promote_precision(this);
  1745. eval_subtract(m_backend, canonical_value(e.value()));
  1746. }
  1747. template <class Exp>
  1748. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::negate&)
  1749. {
  1750. using left_type = typename Exp::left_type;
  1751. do_add(e.left(), typename left_type::tag_type());
  1752. }
  1753. template <class Exp>
  1754. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::plus&)
  1755. {
  1756. using left_type = typename Exp::left_type ;
  1757. using right_type = typename Exp::right_type;
  1758. do_subtract(e.left(), typename left_type::tag_type());
  1759. do_subtract(e.right(), typename right_type::tag_type());
  1760. }
  1761. template <class Exp>
  1762. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::minus&)
  1763. {
  1764. using left_type = typename Exp::left_type ;
  1765. using right_type = typename Exp::right_type;
  1766. do_subtract(e.left(), typename left_type::tag_type());
  1767. do_add(e.right(), typename right_type::tag_type());
  1768. }
  1769. template <class Exp>
  1770. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::add_immediates&)
  1771. {
  1772. using default_ops::eval_subtract;
  1773. boost::multiprecision::detail::maybe_promote_precision(this);
  1774. eval_subtract(m_backend, canonical_value(e.left().value()));
  1775. eval_subtract(m_backend, canonical_value(e.right().value()));
  1776. }
  1777. template <class Exp>
  1778. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const detail::subtract_immediates&)
  1779. {
  1780. using default_ops::eval_add;
  1781. using default_ops::eval_subtract;
  1782. eval_subtract(m_backend, canonical_value(e.left().value()));
  1783. eval_add(m_backend, canonical_value(e.right().value()));
  1784. }
  1785. template <class Exp, class unknown>
  1786. BOOST_MP_CXX14_CONSTEXPR void do_subtract(const Exp& e, const unknown&)
  1787. {
  1788. self_type temp(e);
  1789. do_subtract(detail::expression<detail::terminal, self_type>(temp), detail::terminal());
  1790. }
  1791. template <class Exp>
  1792. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::terminal&)
  1793. {
  1794. using default_ops::eval_multiply;
  1795. boost::multiprecision::detail::maybe_promote_precision(this);
  1796. eval_multiply(m_backend, canonical_value(e.value()));
  1797. }
  1798. template <class Exp>
  1799. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::negate&)
  1800. {
  1801. using left_type = typename Exp::left_type;
  1802. do_multiplies(e.left(), typename left_type::tag_type());
  1803. m_backend.negate();
  1804. }
  1805. template <class Exp>
  1806. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiplies&)
  1807. {
  1808. using left_type = typename Exp::left_type ;
  1809. using right_type = typename Exp::right_type;
  1810. do_multiplies(e.left(), typename left_type::tag_type());
  1811. do_multiplies(e.right(), typename right_type::tag_type());
  1812. }
  1813. //
  1814. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1815. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1816. //
  1817. template <class Exp>
  1818. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1819. do_multiplies(const Exp& e, const detail::divides&)
  1820. {
  1821. using left_type = typename Exp::left_type ;
  1822. using right_type = typename Exp::right_type;
  1823. do_multiplies(e.left(), typename left_type::tag_type());
  1824. do_divide(e.right(), typename right_type::tag_type());
  1825. }
  1826. template <class Exp>
  1827. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const detail::multiply_immediates&)
  1828. {
  1829. using default_ops::eval_multiply;
  1830. boost::multiprecision::detail::maybe_promote_precision(this);
  1831. eval_multiply(m_backend, canonical_value(e.left().value()));
  1832. eval_multiply(m_backend, canonical_value(e.right().value()));
  1833. }
  1834. //
  1835. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1836. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1837. //
  1838. template <class Exp>
  1839. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1840. do_multiplies(const Exp& e, const detail::divide_immediates&)
  1841. {
  1842. using default_ops::eval_divide;
  1843. using default_ops::eval_multiply;
  1844. boost::multiprecision::detail::maybe_promote_precision(this);
  1845. eval_multiply(m_backend, canonical_value(e.left().value()));
  1846. eval_divide(m_backend, canonical_value(e.right().value()));
  1847. }
  1848. template <class Exp, class unknown>
  1849. BOOST_MP_CXX14_CONSTEXPR void do_multiplies(const Exp& e, const unknown&)
  1850. {
  1851. using default_ops::eval_multiply;
  1852. boost::multiprecision::detail::maybe_promote_precision(this);
  1853. self_type temp(e);
  1854. eval_multiply(m_backend, temp.m_backend);
  1855. }
  1856. template <class Exp>
  1857. BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::terminal&)
  1858. {
  1859. using default_ops::eval_divide;
  1860. boost::multiprecision::detail::maybe_promote_precision(this);
  1861. eval_divide(m_backend, canonical_value(e.value()));
  1862. }
  1863. template <class Exp>
  1864. BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const detail::negate&)
  1865. {
  1866. using left_type = typename Exp::left_type;
  1867. do_divide(e.left(), typename left_type::tag_type());
  1868. m_backend.negate();
  1869. }
  1870. //
  1871. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1872. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1873. //
  1874. template <class Exp>
  1875. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1876. do_divide(const Exp& e, const detail::multiplies&)
  1877. {
  1878. using left_type = typename Exp::left_type ;
  1879. using right_type = typename Exp::right_type;
  1880. do_divide(e.left(), typename left_type::tag_type());
  1881. do_divide(e.right(), typename right_type::tag_type());
  1882. }
  1883. //
  1884. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1885. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1886. //
  1887. template <class Exp>
  1888. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1889. do_divide(const Exp& e, const detail::divides&)
  1890. {
  1891. using left_type = typename Exp::left_type ;
  1892. using right_type = typename Exp::right_type;
  1893. do_divide(e.left(), typename left_type::tag_type());
  1894. do_multiplies(e.right(), typename right_type::tag_type());
  1895. }
  1896. //
  1897. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1898. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1899. //
  1900. template <class Exp>
  1901. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1902. do_divides(const Exp& e, const detail::multiply_immediates&)
  1903. {
  1904. using default_ops::eval_divide;
  1905. boost::multiprecision::detail::maybe_promote_precision(this);
  1906. eval_divide(m_backend, canonical_value(e.left().value()));
  1907. eval_divide(m_backend, canonical_value(e.right().value()));
  1908. }
  1909. //
  1910. // This rearrangement is disabled for integer types, the test on sizeof(Exp) is simply to make
  1911. // the disable_if dependent on the template argument (the size of 1 can never occur in practice).
  1912. //
  1913. template <class Exp>
  1914. BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!(boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer || sizeof(Exp) == 1)>::type
  1915. do_divides(const Exp& e, const detail::divide_immediates&)
  1916. {
  1917. using default_ops::eval_divide;
  1918. using default_ops::eval_multiply;
  1919. boost::multiprecision::detail::maybe_promote_precision(this);
  1920. eval_divide(m_backend, canonical_value(e.left().value()));
  1921. mutiply(m_backend, canonical_value(e.right().value()));
  1922. }
  1923. template <class Exp, class unknown>
  1924. BOOST_MP_CXX14_CONSTEXPR void do_divide(const Exp& e, const unknown&)
  1925. {
  1926. using default_ops::eval_multiply;
  1927. boost::multiprecision::detail::maybe_promote_precision(this);
  1928. self_type temp(e);
  1929. eval_divide(m_backend, temp.m_backend);
  1930. }
  1931. template <class Exp>
  1932. BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const detail::terminal&)
  1933. {
  1934. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1935. using default_ops::eval_modulus;
  1936. boost::multiprecision::detail::maybe_promote_precision(this);
  1937. eval_modulus(m_backend, canonical_value(e.value()));
  1938. }
  1939. template <class Exp, class Unknown>
  1940. BOOST_MP_CXX14_CONSTEXPR void do_modulus(const Exp& e, const Unknown&)
  1941. {
  1942. static_assert(number_category<Backend>::value == number_kind_integer, "The modulus operation is only valid for integer types");
  1943. using default_ops::eval_modulus;
  1944. boost::multiprecision::detail::maybe_promote_precision(this);
  1945. self_type temp(e);
  1946. eval_modulus(m_backend, canonical_value(temp));
  1947. }
  1948. template <class Exp>
  1949. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::terminal&)
  1950. {
  1951. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  1952. using default_ops::eval_bitwise_and;
  1953. eval_bitwise_and(m_backend, canonical_value(e.value()));
  1954. }
  1955. template <class Exp>
  1956. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const detail::bitwise_and&)
  1957. {
  1958. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  1959. using left_type = typename Exp::left_type ;
  1960. using right_type = typename Exp::right_type;
  1961. do_bitwise_and(e.left(), typename left_type::tag_type());
  1962. do_bitwise_and(e.right(), typename right_type::tag_type());
  1963. }
  1964. template <class Exp, class unknown>
  1965. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_and(const Exp& e, const unknown&)
  1966. {
  1967. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise & operation is only valid for integer types");
  1968. using default_ops::eval_bitwise_and;
  1969. self_type temp(e);
  1970. eval_bitwise_and(m_backend, temp.m_backend);
  1971. }
  1972. template <class Exp>
  1973. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::terminal&)
  1974. {
  1975. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  1976. using default_ops::eval_bitwise_or;
  1977. eval_bitwise_or(m_backend, canonical_value(e.value()));
  1978. }
  1979. template <class Exp>
  1980. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const detail::bitwise_or&)
  1981. {
  1982. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  1983. using left_type = typename Exp::left_type ;
  1984. using right_type = typename Exp::right_type;
  1985. do_bitwise_or(e.left(), typename left_type::tag_type());
  1986. do_bitwise_or(e.right(), typename right_type::tag_type());
  1987. }
  1988. template <class Exp, class unknown>
  1989. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_or(const Exp& e, const unknown&)
  1990. {
  1991. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise | operation is only valid for integer types");
  1992. using default_ops::eval_bitwise_or;
  1993. self_type temp(e);
  1994. eval_bitwise_or(m_backend, temp.m_backend);
  1995. }
  1996. template <class Exp>
  1997. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::terminal&)
  1998. {
  1999. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  2000. using default_ops::eval_bitwise_xor;
  2001. eval_bitwise_xor(m_backend, canonical_value(e.value()));
  2002. }
  2003. template <class Exp>
  2004. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const detail::bitwise_xor&)
  2005. {
  2006. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  2007. using left_type = typename Exp::left_type ;
  2008. using right_type = typename Exp::right_type;
  2009. do_bitwise_xor(e.left(), typename left_type::tag_type());
  2010. do_bitwise_xor(e.right(), typename right_type::tag_type());
  2011. }
  2012. template <class Exp, class unknown>
  2013. BOOST_MP_CXX14_CONSTEXPR void do_bitwise_xor(const Exp& e, const unknown&)
  2014. {
  2015. static_assert(number_category<Backend>::value == number_kind_integer, "The bitwise ^ operation is only valid for integer types");
  2016. using default_ops::eval_bitwise_xor;
  2017. self_type temp(e);
  2018. eval_bitwise_xor(m_backend, temp.m_backend);
  2019. }
  2020. // Tests if the expression contains a reference to *this:
  2021. template <class Exp>
  2022. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e) const noexcept
  2023. {
  2024. return contains_self(e, typename Exp::arity());
  2025. }
  2026. template <class Exp>
  2027. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
  2028. {
  2029. return is_realy_self(e.value());
  2030. }
  2031. template <class Exp>
  2032. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 1> const&) const noexcept
  2033. {
  2034. using child_type = typename Exp::left_type;
  2035. return contains_self(e.left(), typename child_type::arity());
  2036. }
  2037. template <class Exp>
  2038. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 2> const&) const noexcept
  2039. {
  2040. using child0_type = typename Exp::left_type ;
  2041. using child1_type = typename Exp::right_type;
  2042. return contains_self(e.left(), typename child0_type::arity()) || contains_self(e.right(), typename child1_type::arity());
  2043. }
  2044. template <class Exp>
  2045. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 3> const&) const noexcept
  2046. {
  2047. using child0_type = typename Exp::left_type ;
  2048. using child1_type = typename Exp::middle_type;
  2049. using child2_type = typename Exp::right_type ;
  2050. 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());
  2051. }
  2052. template <class Exp>
  2053. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR bool contains_self(const Exp& e, std::integral_constant<int, 4> const&) const noexcept
  2054. {
  2055. using child0_type = typename Exp::left_type;
  2056. using child1_type = typename Exp::left_middle_type;
  2057. using child2_type = typename Exp::right_middle_type;
  2058. using child3_type = typename Exp::right_type;
  2059. 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());
  2060. }
  2061. // Test if the expression is a reference to *this:
  2062. template <class Exp>
  2063. BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e) const noexcept
  2064. {
  2065. return is_self(e, typename Exp::arity());
  2066. }
  2067. template <class Exp>
  2068. BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp& e, std::integral_constant<int, 0> const&) const noexcept
  2069. {
  2070. return is_realy_self(e.value());
  2071. }
  2072. template <class Exp, int v>
  2073. BOOST_MP_FORCEINLINE constexpr bool is_self(const Exp&, std::integral_constant<int, v> const&) const noexcept
  2074. {
  2075. return false;
  2076. }
  2077. template <class Val>
  2078. BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const Val&) const noexcept { return false; }
  2079. BOOST_MP_FORCEINLINE constexpr bool is_realy_self(const self_type& v) const noexcept { return &v == this; }
  2080. static BOOST_MP_FORCEINLINE constexpr const Backend& function_arg_value(const self_type& v) noexcept { return v.backend(); }
  2081. template <class Other, expression_template_option ET2>
  2082. static BOOST_MP_FORCEINLINE constexpr const Other& function_arg_value(const number<Other, ET2>& v) noexcept { return v.backend(); }
  2083. template <class V>
  2084. static BOOST_MP_FORCEINLINE constexpr const V& function_arg_value(const V& v) noexcept { return v; }
  2085. template <class A1, class A2, class A3, class A4>
  2086. 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(); }
  2087. template <class A2, class A3, class A4>
  2088. 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(); }
  2089. Backend m_backend;
  2090. public:
  2091. //
  2092. // These shouldn't really need to be public, or even member functions, but it makes implementing
  2093. // the non-member operators way easier if they are:
  2094. //
  2095. static BOOST_MP_FORCEINLINE constexpr const Backend& canonical_value(const self_type& v) noexcept { return v.m_backend; }
  2096. template <class B2, expression_template_option ET>
  2097. static BOOST_MP_FORCEINLINE constexpr const B2& canonical_value(const number<B2, ET>& v) noexcept { return v.backend(); }
  2098. template <class B2, expression_template_option ET>
  2099. static BOOST_MP_FORCEINLINE constexpr B2&& canonical_value(number<B2, ET>&& v) noexcept { return static_cast<number<B2, ET>&&>(v).backend(); }
  2100. template <class V>
  2101. 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
  2102. canonical_value(const V& v) noexcept { return static_cast<typename detail::canonical<V, Backend>::type>(v); }
  2103. template <class V>
  2104. static BOOST_MP_FORCEINLINE constexpr typename std::enable_if<std::is_same<typename detail::canonical<V, Backend>::type, V>::value, const V&>::type
  2105. canonical_value(const V& v) noexcept { return v; }
  2106. static BOOST_MP_FORCEINLINE typename detail::canonical<std::string, Backend>::type canonical_value(const std::string& v) noexcept { return v.c_str(); }
  2107. };
  2108. template <class Backend, expression_template_option ExpressionTemplates>
  2109. inline std::ostream& operator<<(std::ostream& os, const number<Backend, ExpressionTemplates>& r)
  2110. {
  2111. std::streamsize d = os.precision();
  2112. std::string s = r.str(d, os.flags());
  2113. std::streamsize ss = os.width();
  2114. if (ss > static_cast<std::streamsize>(s.size()))
  2115. {
  2116. char fill = os.fill();
  2117. if ((os.flags() & std::ios_base::left) == std::ios_base::left)
  2118. s.append(static_cast<std::string::size_type>(ss - static_cast<std::streamsize>(s.size())), fill);
  2119. else
  2120. s.insert(static_cast<std::string::size_type>(0), static_cast<std::string::size_type>(ss - static_cast<std::streamsize>(s.size())), fill);
  2121. }
  2122. return os << s;
  2123. }
  2124. template <class Backend, expression_template_option ExpressionTemplates>
  2125. std::string to_string(const number<Backend, ExpressionTemplates>& val)
  2126. {
  2127. return val.str(6, std::ios_base::fixed|std::ios_base::showpoint);
  2128. }
  2129. namespace detail {
  2130. template <class tag, class A1, class A2, class A3, class A4>
  2131. inline std::ostream& operator<<(std::ostream& os, const expression<tag, A1, A2, A3, A4>& r)
  2132. {
  2133. using value_type = typename expression<tag, A1, A2, A3, A4>::result_type;
  2134. value_type temp(r);
  2135. return os << temp;
  2136. }
  2137. //
  2138. // What follows is the input streaming code: this is not "proper" iostream code at all
  2139. // but that's fiendishly hard to write when dealing with multiple backends all
  2140. // with different requirements... yes we could deligate this to the backend author...
  2141. // but we really want backends to be EASY to write!
  2142. // For now just pull in all the characters that could possibly form the number
  2143. // and let the backend's string parser make use of it. This fixes most use cases
  2144. // including CSV type formats such as those used by the Random lib.
  2145. //
  2146. inline std::string read_string_while(std::istream& is, std::string const& permitted_chars)
  2147. {
  2148. std::ios_base::iostate state = std::ios_base::goodbit;
  2149. const std::istream::sentry sentry_check(is);
  2150. std::string result;
  2151. if (sentry_check)
  2152. {
  2153. int c = is.rdbuf()->sgetc();
  2154. for (;; c = is.rdbuf()->snextc())
  2155. if (std::istream::traits_type::eq_int_type(std::istream::traits_type::eof(), c))
  2156. { // end of file:
  2157. state |= std::ios_base::eofbit;
  2158. break;
  2159. }
  2160. else if (permitted_chars.find_first_of(std::istream::traits_type::to_char_type(c)) == std::string::npos)
  2161. {
  2162. // Invalid numeric character, stop reading:
  2163. //is.rdbuf()->sputbackc(static_cast<char>(c));
  2164. break;
  2165. }
  2166. else
  2167. {
  2168. result.append(1, std::istream::traits_type::to_char_type(c));
  2169. }
  2170. }
  2171. if (!result.size())
  2172. state |= std::ios_base::failbit;
  2173. is.setstate(state);
  2174. return result;
  2175. }
  2176. } // namespace detail
  2177. template <class Backend, expression_template_option ExpressionTemplates>
  2178. inline std::istream& operator>>(std::istream& is, number<Backend, ExpressionTemplates>& r)
  2179. {
  2180. bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
  2181. bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
  2182. std::string s;
  2183. switch (boost::multiprecision::number_category<number<Backend, ExpressionTemplates> >::value)
  2184. {
  2185. case boost::multiprecision::number_kind_integer:
  2186. if (oct_format)
  2187. s = detail::read_string_while(is, "+-01234567");
  2188. else if (hex_format)
  2189. s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789");
  2190. else
  2191. s = detail::read_string_while(is, "+-0123456789");
  2192. break;
  2193. case boost::multiprecision::number_kind_rational:
  2194. if (oct_format)
  2195. s = detail::read_string_while(is, "+-01234567/");
  2196. else if (hex_format)
  2197. s = detail::read_string_while(is, "+-xXabcdefABCDEF0123456789/");
  2198. else
  2199. s = detail::read_string_while(is, "+-0123456789/");
  2200. break;
  2201. case boost::multiprecision::number_kind_floating_point:
  2202. BOOST_IF_CONSTEXPR(std::is_same<number<Backend, ExpressionTemplates>, typename number<Backend, ExpressionTemplates>::value_type>::value)
  2203. s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY");
  2204. else
  2205. // Interval:
  2206. s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY{,}");
  2207. break;
  2208. case boost::multiprecision::number_kind_complex:
  2209. s = detail::read_string_while(is, "+-eE.0123456789infINFnanNANinfinityINFINITY,()");
  2210. break;
  2211. default:
  2212. is >> s;
  2213. }
  2214. if (s.size())
  2215. {
  2216. if (hex_format && (number_category<Backend>::value == number_kind_integer) && ((s[0] != '0') || (s[1] != 'x')))
  2217. s.insert(s.find_first_not_of("+-"), "0x");
  2218. if (oct_format && (number_category<Backend>::value == number_kind_integer) && (s[0] != '0'))
  2219. s.insert(s.find_first_not_of("+-"), "0");
  2220. r.assign(s);
  2221. }
  2222. else if (!is.fail())
  2223. is.setstate(std::istream::failbit);
  2224. return is;
  2225. }
  2226. template <class Backend, expression_template_option ExpressionTemplates>
  2227. BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b)
  2228. noexcept(noexcept(std::declval<number<Backend, ExpressionTemplates>&>() = std::declval<number<Backend, ExpressionTemplates>&>()))
  2229. {
  2230. a.swap(b);
  2231. }
  2232. //
  2233. // Boost.Hash support, just call hash_value for the backend, which may or may not be supported:
  2234. //
  2235. template <class Backend, expression_template_option ExpressionTemplates>
  2236. inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const number<Backend, ExpressionTemplates>& val)
  2237. {
  2238. return hash_value(val.backend());
  2239. }
  2240. namespace detail {
  2241. BOOST_MP_FORCEINLINE bool istream_peek(std::istream& is, char& c, bool have_hex)
  2242. {
  2243. int i = is.peek();
  2244. c = static_cast<char>(i);
  2245. 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')));
  2246. }
  2247. } // namespace detail
  2248. } // namespace multiprecision
  2249. template <class T>
  2250. class rational;
  2251. template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
  2252. inline std::istream& operator>>(std::istream& is, rational<multiprecision::number<Backend, ExpressionTemplates> >& r)
  2253. {
  2254. std::string s1;
  2255. multiprecision::number<Backend, ExpressionTemplates> v1, v2;
  2256. char c;
  2257. bool have_hex = false;
  2258. bool hex_format = (is.flags() & std::ios_base::hex) == std::ios_base::hex;
  2259. bool oct_format = (is.flags() & std::ios_base::oct) == std::ios_base::oct;
  2260. while (multiprecision::detail::istream_peek(is, c, have_hex))
  2261. {
  2262. if (c == 'x' || c == 'X')
  2263. have_hex = true;
  2264. s1.append(1, c);
  2265. is.get();
  2266. }
  2267. if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
  2268. s1.insert(static_cast<std::string::size_type>(0), "0x");
  2269. if (oct_format && (s1[0] != '0'))
  2270. s1.insert(static_cast<std::string::size_type>(0), "0");
  2271. v1.assign(s1);
  2272. s1.erase();
  2273. if (c == '/')
  2274. {
  2275. is.get();
  2276. while (multiprecision::detail::istream_peek(is, c, have_hex))
  2277. {
  2278. if (c == 'x' || c == 'X')
  2279. have_hex = true;
  2280. s1.append(1, c);
  2281. is.get();
  2282. }
  2283. if (hex_format && ((s1[0] != '0') || (s1[1] != 'x')))
  2284. s1.insert(static_cast<std::string::size_type>(0), "0x");
  2285. if (oct_format && (s1[0] != '0'))
  2286. s1.insert(static_cast<std::string::size_type>(0), "0");
  2287. v2.assign(s1);
  2288. }
  2289. else
  2290. v2 = 1;
  2291. r.assign(v1, v2);
  2292. return is;
  2293. }
  2294. template <class T, multiprecision::expression_template_option ExpressionTemplates>
  2295. inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> numerator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
  2296. {
  2297. return a.numerator();
  2298. }
  2299. template <class T, multiprecision::expression_template_option ExpressionTemplates>
  2300. inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<T, ExpressionTemplates> denominator(const rational<multiprecision::number<T, ExpressionTemplates> >& a)
  2301. {
  2302. return a.denominator();
  2303. }
  2304. template <class T, multiprecision::expression_template_option ExpressionTemplates>
  2305. inline BOOST_MP_CXX14_CONSTEXPR std::size_t hash_value(const rational<multiprecision::number<T, ExpressionTemplates> >& val)
  2306. {
  2307. std::size_t result = hash_value(val.numerator());
  2308. boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
  2309. return result;
  2310. }
  2311. namespace multiprecision {
  2312. template <class I>
  2313. struct component_type<boost::rational<I> >
  2314. {
  2315. using type = I;
  2316. };
  2317. } // namespace multiprecision
  2318. #ifdef BOOST_MSVC
  2319. #pragma warning(pop)
  2320. #endif
  2321. } // namespace boost
  2322. namespace std {
  2323. template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
  2324. struct hash<boost::multiprecision::number<Backend, ExpressionTemplates> >
  2325. {
  2326. BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::multiprecision::number<Backend, ExpressionTemplates>& val) const { return hash_value(val); }
  2327. };
  2328. template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
  2329. struct hash<boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> > >
  2330. {
  2331. BOOST_MP_CXX14_CONSTEXPR std::size_t operator()(const boost::rational<boost::multiprecision::number<Backend, ExpressionTemplates> >& val) const
  2332. {
  2333. std::size_t result = hash_value(val.numerator());
  2334. boost::multiprecision::detail::hash_combine(result, hash_value(val.denominator()));
  2335. return result;
  2336. }
  2337. };
  2338. } // namespace std
  2339. #include <boost/multiprecision/detail/ublas_interop.hpp>
  2340. #endif