123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232 |
- ////////////////////////////////////////////////////////////////
- // Copyright 2013 - 2022 John Maddock.
- // Copyright 2022 Christopher Kormanyos.
- // Distributed under the Boost Software License,
- // Version 1.0. (See accompanying file LICENSE_1_0.txt
- // or copy at https://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_MP_CPP_BIN_FLOAT_HPP
- #define BOOST_MP_CPP_BIN_FLOAT_HPP
- #include <cmath>
- #include <cstdint>
- #include <limits>
- #include <type_traits>
- #include <boost/multiprecision/cpp_int.hpp>
- #include <boost/multiprecision/integer.hpp>
- #include <boost/multiprecision/detail/standalone_config.hpp>
- #include <boost/multiprecision/detail/fpclassify.hpp>
- #include <boost/multiprecision/detail/float_string_cvt.hpp>
- #include <boost/multiprecision/traits/max_digits10.hpp>
- #include <boost/multiprecision/detail/hash.hpp>
- #include <boost/multiprecision/detail/no_exceptions_support.hpp>
- #include <boost/multiprecision/detail/assert.hpp>
- #include <boost/multiprecision/detail/float128_functions.hpp>
- #include <boost/multiprecision/detail/functions/trunc.hpp>
- //
- // Some includes we need from Boost.Math, since we rely on that library to provide these functions:
- //
- #ifdef BOOST_MP_MATH_AVAILABLE
- #include <boost/math/special_functions/asinh.hpp>
- #include <boost/math/special_functions/acosh.hpp>
- #include <boost/math/special_functions/atanh.hpp>
- #include <boost/math/special_functions/cbrt.hpp>
- #include <boost/math/special_functions/expm1.hpp>
- #include <boost/math/special_functions/gamma.hpp>
- #endif
- #ifdef BOOST_HAS_FLOAT128
- #include <quadmath.h>
- #endif
- namespace boost {
- namespace multiprecision {
- namespace backends {
- #ifdef BOOST_MSVC
- #pragma warning(push)
- #pragma warning(disable : 4522 6326) // multiple assignment operators specified, comparison of two constants
- #endif
- namespace detail {
- template <class U>
- inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value, bool>::type is_negative(U) { return false; }
- template <class S>
- inline typename std::enable_if< !boost::multiprecision::detail::is_unsigned<S>::value, bool>::type is_negative(S s) { return s < 0; }
- template <class Float, std::ptrdiff_t, bool = number_category<Float>::value == number_kind_floating_point>
- struct is_cpp_bin_float_implicitly_constructible_from_type
- {
- static constexpr bool value = false;
- };
- template <class Float, std::ptrdiff_t bit_count>
- struct is_cpp_bin_float_implicitly_constructible_from_type<Float, bit_count, true>
- {
- static constexpr bool value = (std::numeric_limits<Float>::digits <= static_cast<int>(bit_count)) && (std::numeric_limits<Float>::radix == 2) && std::numeric_limits<Float>::is_specialized
- #ifdef BOOST_HAS_FLOAT128
- && !std::is_same<Float, float128_type>::value
- #endif
- && (std::is_floating_point<Float>::value || is_number<Float>::value);
- };
- template <class Float, std::ptrdiff_t, bool = number_category<Float>::value == number_kind_floating_point>
- struct is_cpp_bin_float_explicitly_constructible_from_type
- {
- static constexpr bool value = false;
- };
- template <class Float, std::ptrdiff_t bit_count>
- struct is_cpp_bin_float_explicitly_constructible_from_type<Float, bit_count, true>
- {
- static constexpr bool value = (std::numeric_limits<Float>::digits > static_cast<int>(bit_count)) && (std::numeric_limits<Float>::radix == 2) && std::numeric_limits<Float>::is_specialized
- #ifdef BOOST_HAS_FLOAT128
- && !std::is_same<Float, float128_type>::value
- #endif
- ;
- };
- } // namespace detail
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinExponent, Exponent MaxExponent>
- class cpp_bin_float
- {
- public:
- static constexpr unsigned bit_count = DigitBase == digit_base_2 ? Digits : (Digits * 1000uL) / 301uL + (((Digits * 1000uL) % 301) ? 2u : 1u);
- using rep_type = cpp_int_backend<std::is_void<Allocator>::value ? bit_count : 0, bit_count, std::is_void<Allocator>::value ? unsigned_magnitude : signed_magnitude, unchecked, Allocator>;
- using double_rep_type = cpp_int_backend<std::is_void<Allocator>::value ? 2 * bit_count : 0, 2 * bit_count, std::is_void<Allocator>::value ? unsigned_magnitude : signed_magnitude, unchecked, Allocator>;
- using signed_types = typename rep_type::signed_types;
- using unsigned_types = typename rep_type::unsigned_types;
- using float_types = std::tuple<float, double, long double>;
- using exponent_type = Exponent;
- static constexpr exponent_type max_exponent_limit = (std::numeric_limits<exponent_type>::max)()- 2 * static_cast<exponent_type>(bit_count);
- static constexpr exponent_type min_exponent_limit = (std::numeric_limits<exponent_type>::min)() + 2 * static_cast<exponent_type>(bit_count);
- static_assert(MinExponent >= min_exponent_limit, "Template parameter MinExponent is too negative for our internal logic to function correctly, sorry!");
- static_assert(MaxExponent <= max_exponent_limit, "Template parameter MaxExponent is too large for our internal logic to function correctly, sorry!");
- static_assert(MinExponent <= 0, "Template parameter MinExponent can not be positive!");
- static_assert(MaxExponent >= 0, "Template parameter MaxExponent can not be negative!");
- static constexpr exponent_type max_exponent = MaxExponent == 0 ? max_exponent_limit : MaxExponent;
- static constexpr exponent_type min_exponent = MinExponent == 0 ? min_exponent_limit : MinExponent;
- static constexpr exponent_type exponent_zero = max_exponent + 1;
- static constexpr exponent_type exponent_infinity = max_exponent + 2;
- static constexpr exponent_type exponent_nan = max_exponent + 3;
- private:
- rep_type m_data;
- exponent_type m_exponent;
- bool m_sign;
- public:
- cpp_bin_float() noexcept(noexcept(rep_type())) : m_data(), m_exponent(exponent_zero), m_sign(false) {}
- cpp_bin_float(const cpp_bin_float& o) noexcept(noexcept(rep_type(std::declval<const rep_type&>())))
- : m_data(o.m_data), m_exponent(o.m_exponent), m_sign(o.m_sign) {}
- template <unsigned D, digit_base_type B, class A, class E, E MinE, E MaxE>
- cpp_bin_float(const cpp_bin_float<D, B, A, E, MinE, MaxE>& o, typename std::enable_if<(bit_count >= cpp_bin_float<D, B, A, E, MinE, MaxE>::bit_count)>::type const* = nullptr)
- {
- *this = o;
- }
- template <unsigned D, digit_base_type B, class A, class E, E MinE, E MaxE>
- explicit cpp_bin_float(const cpp_bin_float<D, B, A, E, MinE, MaxE>& o, typename std::enable_if< !(bit_count >= cpp_bin_float<D, B, A, E, MinE, MaxE>::bit_count)>::type const* = nullptr)
- : m_exponent(o.exponent()), m_sign(o.sign())
- {
- *this = o;
- }
- // rvalue copy:
- template <unsigned D, digit_base_type B, class A, class E, E MinE, E MaxE>
- cpp_bin_float(cpp_bin_float<D, B, A, E, MinE, MaxE>&& o, typename std::enable_if<(bit_count >= cpp_bin_float<D, B, A, E, MinE, MaxE>::bit_count)>::type const* = nullptr)noexcept(noexcept(rep_type(std::declval<rep_type&&>())))
- {
- *this = std::move(o);
- }
- template <unsigned D, digit_base_type B, class A, class E, E MinE, E MaxE>
- explicit cpp_bin_float(cpp_bin_float<D, B, A, E, MinE, MaxE>&& o, typename std::enable_if< !(bit_count >= cpp_bin_float<D, B, A, E, MinE, MaxE>::bit_count)>::type const* = nullptr) noexcept(noexcept(rep_type(std::declval<rep_type&&>())))
- : m_exponent(o.exponent()), m_sign(o.sign())
- {
- *this = std::move(o);
- }
- template <class Float>
- cpp_bin_float(const Float& f,
- typename std::enable_if<detail::is_cpp_bin_float_implicitly_constructible_from_type<Float, static_cast<std::ptrdiff_t>(bit_count)>::value>::type const* = nullptr)
- : m_data(), m_exponent(0), m_sign(false)
- {
- this->assign_float(f);
- }
- template <class Float>
- explicit cpp_bin_float(const Float& f,
- typename std::enable_if<detail::is_cpp_bin_float_explicitly_constructible_from_type<Float, static_cast<std::ptrdiff_t>(bit_count)>::value>::type const* = nullptr)
- : m_data(), m_exponent(0), m_sign(false)
- {
- this->assign_float(f);
- }
- #ifdef BOOST_HAS_FLOAT128
- template <class Float>
- cpp_bin_float(const Float& f,
- typename std::enable_if<
- std::is_same<Float, float128_type>::value && (static_cast<int>(bit_count) >= 113)>::type const* = nullptr)
- : m_data(), m_exponent(0), m_sign(false)
- {
- this->assign_float(f);
- }
- template <class Float>
- explicit cpp_bin_float(const Float& f,
- typename std::enable_if<
- std::is_same<Float, float128_type>::value && (static_cast<int>(bit_count) < 113)>::type const* = nullptr)
- : m_data(), m_exponent(0), m_sign(false)
- {
- this->assign_float(f);
- }
- #endif
- cpp_bin_float& operator=(const cpp_bin_float& o) noexcept(noexcept(std::declval<rep_type&>() = std::declval<const rep_type&>()))
- {
- m_data = o.m_data;
- m_exponent = o.m_exponent;
- m_sign = o.m_sign;
- return *this;
- }
- template <class A, class E, E MinE, E MaxE>
- cpp_bin_float& operator=(const cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>& o) noexcept(noexcept(std::declval<rep_type&>() = std::declval<const rep_type&>()))
- {
- m_data = o.bits();
- m_sign = o.sign();
- if (o.exponent() == cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>::exponent_zero)
- m_exponent = exponent_zero;
- else if (o.exponent() == cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>::exponent_nan)
- m_exponent = exponent_nan;
- else if (o.exponent() == cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>::exponent_infinity)
- m_exponent = exponent_infinity;
- else if (o.exponent() > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
- {
- // Overflow:
- exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
- bits() = static_cast<limb_type>(0u);
- }
- else if (o.exponent() < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
- {
- // Underflow:
- exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- bits() = static_cast<limb_type>(0u);
- }
- else
- m_exponent = o.exponent();
- return *this;
- }
- // rvalue copy:
- template <class A, class E, E MinE, E MaxE>
- cpp_bin_float& operator=(cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>&& o) noexcept(noexcept(std::declval<rep_type&>() = std::declval<rep_type&&>()))
- {
- m_data = std::move(o.bits());
- m_sign = o.sign();
- if (o.exponent() == cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>::exponent_zero)
- m_exponent = exponent_zero;
- else if (o.exponent() == cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>::exponent_nan)
- m_exponent = exponent_nan;
- else if (o.exponent() == cpp_bin_float<Digits, DigitBase, A, E, MinE, MaxE>::exponent_infinity)
- m_exponent = exponent_infinity;
- else if (o.exponent() > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
- {
- // Overflow:
- exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
- bits() = static_cast<limb_type>(0u);
- }
- else if (o.exponent() < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
- {
- // Underflow:
- exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- bits() = static_cast<limb_type>(0u);
- }
- else
- m_exponent = o.exponent();
- return *this;
- }
- template <unsigned D, digit_base_type B, class A, class E, E MinE, E MaxE>
- cpp_bin_float& operator=(const cpp_bin_float<D, B, A, E, MinE, MaxE>& f)
- {
- switch (eval_fpclassify(f))
- {
- case FP_ZERO:
- m_data = limb_type(0);
- m_sign = f.sign();
- m_exponent = exponent_zero;
- break;
- case FP_NAN:
- m_data = limb_type(0);
- m_sign = false;
- m_exponent = exponent_nan;
- break;
- ;
- case FP_INFINITE:
- m_data = limb_type(0);
- m_sign = f.sign();
- m_exponent = exponent_infinity;
- break;
- default:
- typename cpp_bin_float<D, B, A, E, MinE, MaxE>::rep_type b(f.bits());
- this->exponent() = f.exponent() + (E)bit_count - (E)cpp_bin_float<D, B, A, E, MinE, MaxE>::bit_count;
- this->sign() = f.sign();
- copy_and_round(*this, b);
- }
- return *this;
- }
- #ifdef BOOST_HAS_FLOAT128
- template <class Float>
- typename std::enable_if<
- (number_category<Float>::value == number_kind_floating_point)
- //&& (std::numeric_limits<Float>::digits <= static_cast<int>(bit_count))
- && ((std::numeric_limits<Float>::radix == 2) || (std::is_same<Float, float128_type>::value)),
- cpp_bin_float&>::type
- operator=(const Float& f)
- #else
- template <class Float>
- typename std::enable_if<
- (number_category<Float>::value == number_kind_floating_point)
- //&& (std::numeric_limits<Float>::digits <= static_cast<int>(bit_count))
- && (std::numeric_limits<Float>::radix == 2),
- cpp_bin_float&>::type
- operator=(const Float& f)
- #endif
- {
- return assign_float(f);
- }
- #ifdef BOOST_HAS_FLOAT128
- template <class Float>
- typename std::enable_if<std::is_same<Float, float128_type>::value, cpp_bin_float&>::type assign_float(Float f)
- {
- using default_ops::eval_add;
- using bf_int_type = typename boost::multiprecision::detail::canonical<int, cpp_bin_float>::type;
- if (f == 0)
- {
- m_data = limb_type(0);
- m_sign = (signbitq(f) > 0);
- m_exponent = exponent_zero;
- return *this;
- }
- else if (isnanq(f))
- {
- m_data = limb_type(0);
- m_sign = false;
- m_exponent = exponent_nan;
- return *this;
- }
- else if (isinfq(f))
- {
- m_data = limb_type(0);
- m_sign = (f < 0);
- m_exponent = exponent_infinity;
- return *this;
- }
- if (f < 0)
- {
- *this = -f;
- this->negate();
- return *this;
- }
- using ui_type = typename std::tuple_element<0, unsigned_types>::type;
- m_data = static_cast<ui_type>(0u);
- m_sign = false;
- m_exponent = 0;
- constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1;
- int e;
- f = frexpq(f, &e);
- while (f)
- {
- f = ldexpq(f, bits);
- e -= bits;
- int ipart = static_cast<int>(truncq(f));
- f -= ipart;
- m_exponent += bits;
- cpp_bin_float t;
- t = static_cast<bf_int_type>(ipart);
- eval_add(*this, t);
- }
- m_exponent += static_cast<Exponent>(e);
- return *this;
- }
- #endif
- #ifdef BOOST_HAS_FLOAT128
- template <class Float>
- typename std::enable_if<std::is_floating_point<Float>::value && !std::is_same<Float, float128_type>::value, cpp_bin_float&>::type assign_float(Float f)
- #else
- template <class Float>
- typename std::enable_if<std::is_floating_point<Float>::value, cpp_bin_float&>::type assign_float(Float f)
- #endif
- {
- using std::frexp;
- using std::ldexp;
- using std::signbit;
- using default_ops::eval_add;
- using bf_int_type = typename boost::multiprecision::detail::canonical<int, cpp_bin_float>::type;
- switch (BOOST_MP_FPCLASSIFY(f))
- {
- case FP_ZERO:
- m_data = limb_type(0);
- m_sign = ((signbit)(f));
- m_exponent = exponent_zero;
- return *this;
- case FP_NAN:
- m_data = limb_type(0);
- m_sign = false;
- m_exponent = exponent_nan;
- return *this;
- case FP_INFINITE:
- m_data = limb_type(0);
- m_sign = (f < 0);
- m_exponent = exponent_infinity;
- return *this;
- }
- if (f < 0)
- {
- *this = -f;
- this->negate();
- return *this;
- }
- using ui_type = typename std::tuple_element<0, unsigned_types>::type;
- m_data = static_cast<ui_type>(0u);
- m_sign = false;
- m_exponent = 0;
- constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1;
- int e;
- f = frexp(f, &e);
- while (f != static_cast<Float>(0.0F))
- {
- f = ldexp(f, bits);
- e -= static_cast<int>(bits);
- int ipart = boost::multiprecision::detail::itrunc(f);
- f -= static_cast<Float>(ipart);
- m_exponent += static_cast<exponent_type>(bits);
- cpp_bin_float t;
- t = static_cast<bf_int_type>(ipart);
- eval_add(*this, t);
- }
- m_exponent += static_cast<Exponent>(e);
- return *this;
- }
- template <class Float>
- typename std::enable_if<
- (number_category<Float>::value == number_kind_floating_point) && !std::is_floating_point<Float>::value && (number_category<Float>::value == number_kind_floating_point),
- cpp_bin_float&>::type
- assign_float(Float f)
- {
- using default_ops::eval_add;
- using default_ops::eval_convert_to;
- using default_ops::eval_get_sign;
- using default_ops::eval_subtract;
- using f_int_type = typename boost::multiprecision::detail::canonical<int, Float>::type ;
- using bf_int_type = typename boost::multiprecision::detail::canonical<int, cpp_bin_float>::type;
- switch (eval_fpclassify(f))
- {
- case FP_ZERO:
- m_data = limb_type(0);
- m_sign = (eval_get_sign(f) > 0);
- m_exponent = exponent_zero;
- return *this;
- case FP_NAN:
- m_data = limb_type(0);
- m_sign = false;
- m_exponent = exponent_nan;
- return *this;
- case FP_INFINITE:
- m_data = limb_type(0);
- m_sign = eval_get_sign(f) < 0;
- m_exponent = exponent_infinity;
- return *this;
- }
- if (eval_get_sign(f) < 0)
- {
- f.negate();
- assign_float(f);
- this->negate();
- return *this;
- }
- using ui_type = typename std::tuple_element<0, unsigned_types>::type;
- m_data = static_cast<ui_type>(0u);
- m_sign = false;
- m_exponent = 0;
- constexpr std::ptrdiff_t bits = sizeof(int) * CHAR_BIT - 1;
- int e;
- eval_frexp(f, f, &e);
- while (eval_get_sign(f) != 0)
- {
- eval_ldexp(f, f, bits);
- e -= bits;
- int ipart;
- eval_convert_to(&ipart, f);
- eval_subtract(f, static_cast<f_int_type>(ipart));
- m_exponent += bits;
- eval_add(*this, static_cast<bf_int_type>(ipart));
- }
- m_exponent += e;
- if (m_exponent > max_exponent)
- m_exponent = exponent_infinity;
- if (m_exponent < min_exponent)
- {
- m_data = limb_type(0u);
- m_exponent = exponent_zero;
- m_sign = (eval_get_sign(f) > 0);
- }
- else if (eval_get_sign(m_data) == 0)
- {
- m_exponent = exponent_zero;
- m_sign = (eval_get_sign(f) > 0);
- }
- return *this;
- }
- template <class B, expression_template_option et>
- cpp_bin_float& assign_float(const number<B, et>& f)
- {
- return assign_float(f.backend());
- }
-
- template <class I>
- typename std::enable_if<boost::multiprecision::detail::is_integral<I>::value, cpp_bin_float&>::type operator=(const I& i)
- {
- using default_ops::eval_bit_test;
- if (!i)
- {
- m_data = static_cast<limb_type>(0);
- m_exponent = exponent_zero;
- m_sign = false;
- }
- else
- {
- using ui_type = typename boost::multiprecision::detail::make_unsigned<I>::type ;
- ui_type fi = static_cast<ui_type>(boost::multiprecision::detail::unsigned_abs(i));
- using ar_type = typename boost::multiprecision::detail::canonical<ui_type, rep_type>::type;
- m_data = static_cast<ar_type>(fi);
- std::size_t shift = msb(fi);
- if (shift >= bit_count)
- {
- m_exponent = static_cast<Exponent>(shift);
- m_data = static_cast<ar_type>(fi >> (shift + 1 - bit_count));
- }
- else
- {
- m_exponent = static_cast<Exponent>(shift);
- eval_left_shift(m_data, bit_count - shift - 1);
- }
- BOOST_MP_ASSERT(eval_bit_test(m_data, bit_count - 1));
- m_sign = detail::is_negative(i);
- }
- return *this;
- }
- cpp_bin_float& operator=(const char* s);
- void swap(cpp_bin_float& o) noexcept
- {
- m_data.swap(o.m_data);
- std::swap(m_exponent, o.m_exponent);
- std::swap(m_sign, o.m_sign);
- }
- std::string str(std::streamsize dig, std::ios_base::fmtflags f) const;
- void negate()
- {
- if (m_exponent != exponent_nan)
- m_sign = !m_sign;
- }
- int compare(const cpp_bin_float& o) const noexcept
- {
- if (m_sign != o.m_sign)
- return (m_exponent == exponent_zero) && (m_exponent == o.m_exponent) ? 0 : m_sign ? -1 : 1;
- int result;
- if (m_exponent == exponent_nan)
- return -1;
- else if (m_exponent != o.m_exponent)
- {
- if (m_exponent == exponent_zero)
- result = -1;
- else if (o.m_exponent == exponent_zero)
- result = 1;
- else
- result = m_exponent > o.m_exponent ? 1 : -1;
- }
- else
- result = m_data.compare(o.m_data);
- if (m_sign)
- result = -result;
- return result;
- }
- template <class A>
- int compare(const A& o) const noexcept
- {
- cpp_bin_float b;
- b = o;
- return compare(b);
- }
- rep_type& bits() { return m_data; }
- const rep_type& bits() const { return m_data; }
- exponent_type& exponent() { return m_exponent; }
- const exponent_type& exponent() const { return m_exponent; }
- bool& sign() { return m_sign; }
- const bool& sign() const { return m_sign; }
- void check_invariants()
- {
- using default_ops::eval_bit_test;
- using default_ops::eval_is_zero;
- if ((m_exponent <= max_exponent) && (m_exponent >= min_exponent))
- {
- BOOST_MP_ASSERT(eval_bit_test(m_data, bit_count - 1));
- }
- else
- {
- BOOST_MP_ASSERT(m_exponent > max_exponent);
- BOOST_MP_ASSERT(m_exponent <= exponent_nan);
- BOOST_MP_ASSERT(eval_is_zero(m_data));
- }
- }
- #ifndef BOOST_MP_STANDALONE
- template <class Archive>
- void serialize(Archive& ar, const unsigned int /*version*/)
- {
- ar& boost::make_nvp("data", m_data);
- ar& boost::make_nvp("exponent", m_exponent);
- ar& boost::make_nvp("sign", m_sign);
- }
- #endif
- };
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class Int>
- inline void copy_and_round(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, Int& arg, std::ptrdiff_t bits_to_keep = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count)
- {
- // Precondition: exponent of res must have been set before this function is called
- // as we may need to adjust it based on how many bits_to_keep in arg are set.
- using default_ops::eval_bit_test;
- using default_ops::eval_get_sign;
- using default_ops::eval_increment;
- using default_ops::eval_left_shift;
- using default_ops::eval_lsb;
- using default_ops::eval_msb;
- using default_ops::eval_right_shift;
- // cancellation may have resulted in arg being all zeros:
- if (eval_get_sign(arg) == 0)
- {
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- res.sign() = false;
- res.bits() = static_cast<limb_type>(0u);
- return;
- }
- std::ptrdiff_t msb = static_cast<std::ptrdiff_t>(eval_msb(arg));
- if (static_cast<std::ptrdiff_t >(bits_to_keep) > msb + 1)
- {
- // Must have had cancellation in subtraction,
- // or be converting from a narrower type, so shift left:
- res.bits() = arg;
- eval_left_shift(res.bits(), static_cast<double_limb_type>(bits_to_keep - msb - 1));
- res.exponent() -= static_cast<Exponent>(bits_to_keep - msb - 1);
- }
- else if (static_cast<std::ptrdiff_t >(bits_to_keep) < msb + 1)
- {
- // We have more bits_to_keep than we need, so round as required,
- // first get the rounding bit:
- bool roundup = eval_bit_test(arg, static_cast<std::size_t>(msb - bits_to_keep));
- // Then check for a tie:
- if (roundup && (msb - bits_to_keep == static_cast<std::ptrdiff_t>(eval_lsb(arg))))
- {
- // Ties round towards even:
- if (!eval_bit_test(arg, static_cast<std::size_t>(msb - bits_to_keep + 1)))
- roundup = false;
- }
- // Shift off the bits_to_keep we don't need:
- eval_right_shift(arg, static_cast<double_limb_type>(msb - bits_to_keep + 1));
- res.exponent() += static_cast<Exponent>(msb - bits_to_keep + 1);
- if (roundup)
- {
- eval_increment(arg);
- if (bits_to_keep)
- {
- if (eval_bit_test(arg, static_cast<std::size_t>(bits_to_keep)))
- {
- // This happens very very rairly, all the bits left after
- // truncation must be 1's and we're rounding up an order of magnitude:
- eval_right_shift(arg, 1u);
- ++res.exponent();
- }
- }
- else
- {
- // We get here when bits_to_keep is zero but we're rounding up,
- // as a result we end up with a single digit that is a 1:
- ++bits_to_keep;
- }
- }
- if (bits_to_keep != cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count)
- {
- // Normalize result when we're rounding to fewer bits than we can hold, only happens in conversions
- // to narrower types:
- eval_left_shift(arg, static_cast<double_limb_type>(static_cast<std::ptrdiff_t>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - bits_to_keep));
- res.exponent() -= static_cast<Exponent>(static_cast<std::ptrdiff_t>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - bits_to_keep);
- }
- res.bits() = arg;
- }
- else
- {
- res.bits() = arg;
- }
- if (!bits_to_keep && !res.bits().limbs()[0])
- {
- // We're keeping zero bits and did not round up, so result is zero:
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- return;
- }
- // Result must be normalized:
- BOOST_MP_ASSERT(((std::ptrdiff_t )eval_msb(res.bits()) == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1));
- if (res.exponent() > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent)
- {
- // Overflow:
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
- res.bits() = static_cast<limb_type>(0u);
- }
- else if (res.exponent() < cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent)
- {
- // Underflow:
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- res.bits() = static_cast<limb_type>(0u);
- }
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class BinFloat2, class BinFloat3>
- inline void do_eval_add(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const BinFloat2& a, const BinFloat3& b)
- {
- if (a.exponent() < b.exponent())
- {
- bool s = a.sign();
- do_eval_add(res, b, a);
- if (res.sign() != s)
- res.negate();
- return;
- }
- using default_ops::eval_add;
- using default_ops::eval_bit_test;
- using exponent_type = typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type;
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type dt;
- // Special cases first:
- switch (a.exponent())
- {
- case BinFloat2::exponent_zero:
- {
- bool s = a.sign();
- res = b;
- res.sign() = s;
- return;
- }
- case BinFloat2::exponent_infinity:
- if (b.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan)
- res = b;
- else
- res = a;
- return; // result is still infinite.
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- res = a;
- return; // result is still a NaN.
- }
- switch (b.exponent())
- {
- case BinFloat3::exponent_zero:
- res = a;
- return;
- case BinFloat3::exponent_infinity:
- res = b;
- if (res.sign())
- res.negate();
- return; // result is infinite.
- case BinFloat3::exponent_nan:
- res = b;
- return; // result is a NaN.
- }
- static_assert((std::numeric_limits<exponent_type>::max)() - cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count > cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent, "Exponent range check failed");
- bool s = a.sign();
- dt = a.bits();
- if (a.exponent() > (std::ptrdiff_t )cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + b.exponent())
- {
- res.exponent() = a.exponent();
- }
- else
- {
- exponent_type e_diff = a.exponent() - b.exponent();
- BOOST_MP_ASSERT(e_diff >= 0);
- eval_left_shift(dt, static_cast<double_limb_type>(e_diff));
- res.exponent() = a.exponent() - e_diff;
- eval_add(dt, b.bits());
- }
- copy_and_round(res, dt);
- res.check_invariants();
- if (res.sign() != s)
- res.negate();
- }
- template <class BinFloat1, class BinFloat2, class BinFloat3>
- inline void do_eval_subtract(BinFloat1& res, const BinFloat2& a, const BinFloat3& b)
- {
- using default_ops::eval_bit_test;
- using default_ops::eval_decrement;
- using default_ops::eval_subtract;
- typename BinFloat1::double_rep_type dt;
- // Special cases first:
- switch (a.exponent())
- {
- case BinFloat2::exponent_zero:
- if (b.exponent() == BinFloat3::exponent_nan)
- res = std::numeric_limits<number<BinFloat1> >::quiet_NaN().backend();
- else
- {
- bool s = a.sign();
- res = b;
- if (res.exponent() == BinFloat1::exponent_zero)
- res.sign() = false;
- else if (res.sign() == s)
- res.negate();
- }
- return;
- case BinFloat2::exponent_infinity:
- if ((b.exponent() == BinFloat3::exponent_nan) || (b.exponent() == BinFloat3::exponent_infinity))
- res = std::numeric_limits<number<BinFloat1> >::quiet_NaN().backend();
- else
- res = a;
- return;
- case BinFloat2::exponent_nan:
- res = a;
- return; // result is still a NaN.
- }
- switch (b.exponent())
- {
- case BinFloat3::exponent_zero:
- res = a;
- return;
- case BinFloat3::exponent_infinity:
- res.exponent() = BinFloat1::exponent_infinity;
- res.sign() = !a.sign();
- res.bits() = static_cast<limb_type>(0u);
- return; // result is a NaN.
- case BinFloat3::exponent_nan:
- res = b;
- return; // result is still a NaN.
- }
- bool s = a.sign();
- if ((a.exponent() > b.exponent()) || ((a.exponent() == b.exponent()) && a.bits().compare(b.bits()) >= 0))
- {
- dt = a.bits();
- if (a.exponent() <= (std::ptrdiff_t )BinFloat1::bit_count + b.exponent())
- {
- typename BinFloat1::exponent_type e_diff = a.exponent() - b.exponent();
- eval_left_shift(dt, static_cast<double_limb_type>(e_diff));
- res.exponent() = a.exponent() - e_diff;
- eval_subtract(dt, b.bits());
- }
- else if (a.exponent() == (std::ptrdiff_t )BinFloat1::bit_count + b.exponent() + 1)
- {
- if ((eval_lsb(a.bits()) == BinFloat1::bit_count - 1)
- && (eval_lsb(b.bits()) != BinFloat1::bit_count - 1))
- {
- eval_left_shift(dt, 1);
- eval_decrement(dt);
- res.exponent() = a.exponent() - 1;
- }
- else
- res.exponent() = a.exponent();
- }
- else
- res.exponent() = a.exponent();
- }
- else
- {
- dt = b.bits();
- if (b.exponent() <= (std::ptrdiff_t )BinFloat1::bit_count + a.exponent())
- {
- typename BinFloat1::exponent_type e_diff = a.exponent() - b.exponent();
- eval_left_shift(dt, static_cast<double_limb_type>(-e_diff));
- res.exponent() = b.exponent() + e_diff;
- eval_subtract(dt, a.bits());
- }
- else if (b.exponent() == (std::ptrdiff_t )BinFloat1::bit_count + a.exponent() + 1)
- {
- if ((eval_lsb(a.bits()) != BinFloat1::bit_count - 1)
- && eval_lsb(b.bits()))
- {
- eval_left_shift(dt, 1);
- eval_decrement(dt);
- res.exponent() = b.exponent() - 1;
- }
- else
- res.exponent() = b.exponent();
- }
- else
- res.exponent() = b.exponent();
- s = !s;
- }
- copy_and_round(res, dt);
- if (res.exponent() == BinFloat1::exponent_zero)
- res.sign() = false;
- else if (res.sign() != s)
- res.negate();
- res.check_invariants();
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2,
- class Allocator3, class Exponent3, Exponent MinE3, Exponent MaxE3>
- inline void eval_add(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a,
- const cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>& b)
- {
- if (a.sign() == b.sign())
- do_eval_add(res, a, b);
- else
- do_eval_subtract(res, a, b);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- inline void eval_add(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a)
- {
- return eval_add(res, res, a);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2,
- class Allocator3, class Exponent3, Exponent MinE3, Exponent MaxE3>
- inline void eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a,
- const cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>& b)
- {
- if (a.sign() != b.sign())
- do_eval_add(res, a, b);
- else
- do_eval_subtract(res, a, b);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- inline void eval_subtract(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a)
- {
- return eval_subtract(res, res, a);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2,
- class Allocator3, class Exponent3, Exponent MinE3, Exponent MaxE3>
- inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a,
- const cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>& b)
- {
- using default_ops::eval_bit_test;
- using default_ops::eval_multiply;
- // Special cases first:
- switch (a.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_zero:
- {
- if (b.exponent() == cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_nan)
- res = b;
- else if (b.exponent() == cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_infinity)
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- else
- {
- bool s = a.sign() != b.sign();
- res = a;
- res.sign() = s;
- }
- return;
- }
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_infinity:
- switch (b.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_zero:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- break;
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_nan:
- res = b;
- break;
- default:
- bool s = a.sign() != b.sign();
- res = a;
- res.sign() = s;
- break;
- }
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_nan:
- res = a;
- return;
- }
- if (b.exponent() > cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::max_exponent)
- {
- bool s = a.sign() != b.sign();
- res = b;
- res.sign() = s;
- return;
- }
- if ((a.exponent() > 0) && (b.exponent() > 0))
- {
- if (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent + 2 - a.exponent() < b.exponent())
- {
- // We will certainly overflow:
- bool s = a.sign() != b.sign();
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
- res.sign() = s;
- res.bits() = static_cast<limb_type>(0u);
- return;
- }
- }
- if ((a.exponent() < 0) && (b.exponent() < 0))
- {
- if (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent - 2 - a.exponent() > b.exponent())
- {
- // We will certainly underflow:
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- res.sign() = a.sign() != b.sign();
- res.bits() = static_cast<limb_type>(0u);
- return;
- }
- }
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type dt;
- eval_multiply(dt, a.bits(), b.bits());
- res.exponent() = a.exponent() + b.exponent() - (Exponent)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count + 1;
- copy_and_round(res, dt);
- res.check_invariants();
- res.sign() = a.sign() != b.sign();
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- inline void eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a)
- {
- eval_multiply(res, res, a);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2, class U>
- inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value>::type eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a, const U& b)
- {
- using default_ops::eval_bit_test;
- using default_ops::eval_multiply;
- bool s = a.sign(); // saved for later in case a and res are the same object.
- // Special cases first:
- switch (a.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_zero:
- {
- res = a;
- res.sign() = s;
- return;
- }
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_infinity:
- if (b == 0)
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- else
- res = a;
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_nan:
- res = a;
- return;
- }
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type dt;
- using canon_ui_type = typename boost::multiprecision::detail::canonical<U, typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type>::type;
- eval_multiply(dt, a.bits(), static_cast<canon_ui_type>(b));
- res.exponent() = a.exponent();
- copy_and_round(res, dt);
- res.check_invariants();
- res.sign() = s;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class U>
- inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value>::type eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const U& b)
- {
- eval_multiply(res, res, b);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2, class S>
- inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value>::type eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& a, const S& b)
- {
- using ui_type = typename boost::multiprecision::detail::make_unsigned<S>::type;
- eval_multiply(res, a, static_cast<ui_type>(boost::multiprecision::detail::unsigned_abs(b)));
- if (b < 0)
- res.negate();
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class S>
- inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value>::type eval_multiply(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const S& b)
- {
- eval_multiply(res, res, b);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2,
- class Allocator3, class Exponent3, Exponent MinE3, Exponent MaxE3>
- inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& u,
- const cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>& v)
- {
- #ifdef BOOST_MSVC
- #pragma warning(push)
- #pragma warning(disable : 6326) // comparison of two constants
- #endif
- using default_ops::eval_bit_test;
- using default_ops::eval_get_sign;
- using default_ops::eval_increment;
- using default_ops::eval_qr;
- using default_ops::eval_subtract;
- //
- // Special cases first:
- //
- switch (u.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_zero:
- {
- switch (v.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_zero:
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_nan:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- return;
- }
- bool s = u.sign() != v.sign();
- res = u;
- res.sign() = s;
- return;
- }
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_infinity:
- {
- switch (v.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_infinity:
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_nan:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- return;
- }
- bool s = u.sign() != v.sign();
- res = u;
- res.sign() = s;
- return;
- }
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_nan:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- return;
- }
- switch (v.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_zero:
- {
- bool s = u.sign() != v.sign();
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
- res.sign() = s;
- return;
- }
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_infinity:
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- res.bits() = limb_type(0);
- res.sign() = u.sign() != v.sign();
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator3, Exponent3, MinE3, MaxE3>::exponent_nan:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- return;
- }
- // We can scale u and v so that both are integers, then perform integer
- // division to obtain quotient q and remainder r, such that:
- //
- // q * v + r = u
- //
- // and hense:
- //
- // q + r/v = u/v
- //
- // From this, assuming q has cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count
- // bits we only need to determine whether
- // r/v is less than, equal to, or greater than 0.5 to determine rounding -
- // this we can do with a shift and comparison.
- //
- // We can set the exponent and sign of the result up front:
- //
- if ((v.exponent() < 0) && (u.exponent() > 0))
- {
- // Check for overflow:
- if (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent + v.exponent() < u.exponent() - 1)
- {
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
- res.sign() = u.sign() != v.sign();
- res.bits() = static_cast<limb_type>(0u);
- return;
- }
- }
- else if ((v.exponent() > 0) && (u.exponent() < 0))
- {
- // Check for underflow:
- if (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent + v.exponent() > u.exponent())
- {
- // We will certainly underflow:
- res.exponent() = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- res.sign() = u.sign() != v.sign();
- res.bits() = static_cast<limb_type>(0u);
- return;
- }
- }
- res.exponent() = u.exponent() - v.exponent() - 1;
- res.sign() = u.sign() != v.sign();
- //
- // Now get the quotient and remainder:
- //
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type t(u.bits()), t2(v.bits()), q, r;
- eval_left_shift(t, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count);
- eval_qr(t, t2, q, r);
- //
- // We now have either "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count"
- // or "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count+1" significant
- // bits in q.
- //
- constexpr unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
- if (eval_bit_test(q, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count))
- {
- //
- // OK we have cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count+1 bits,
- // so we already have rounding info,
- // we just need to changes things if the last bit is 1 and either the
- // remainder is non-zero (ie we do not have a tie) or the quotient would
- // be odd if it were shifted to the correct number of bits (ie a tiebreak).
- //
- BOOST_MP_ASSERT((eval_msb(q) == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count));
- if ((q.limbs()[0] & 1u) && (eval_get_sign(r) || (q.limbs()[0] & 2u)))
- {
- eval_increment(q);
- }
- }
- else
- {
- //
- // We have exactly "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count" bits in q.
- // Get rounding info, which we can get by comparing 2r with v.
- // We want to call copy_and_round to handle rounding and general cleanup,
- // so we'll left shift q and add some fake digits on the end to represent
- // how we'll be rounding.
- //
- using local_exponent_type = typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type;
- BOOST_MP_ASSERT((eval_msb(q) == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1));
- constexpr unsigned lshift = (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count < limb_bits) ? 2 : limb_bits;
- eval_left_shift(q, lshift);
- res.exponent() -= static_cast<local_exponent_type>(lshift);
- eval_left_shift(r, 1u);
- int c = r.compare(v.bits());
- if (c == 0)
- q.limbs()[0] |= static_cast<limb_type>(1u) << (lshift - 1);
- else if (c > 0)
- q.limbs()[0] |= (static_cast<limb_type>(1u) << (lshift - 1)) + static_cast<limb_type>(1u);
- }
- copy_and_round(res, q);
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- inline void eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& arg)
- {
- eval_divide(res, res, arg);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2, class U>
- inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& u, const U& v)
- {
- #ifdef BOOST_MSVC
- #pragma warning(push)
- #pragma warning(disable : 6326) // comparison of two constants
- #endif
- using default_ops::eval_bit_test;
- using default_ops::eval_get_sign;
- using default_ops::eval_increment;
- using default_ops::eval_qr;
- using default_ops::eval_subtract;
- //
- // Special cases first:
- //
- switch (u.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_zero:
- {
- if (v == 0)
- {
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- return;
- }
- bool s = u.sign() != (v < 0);
- res = u;
- res.sign() = s;
- return;
- }
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_infinity:
- res = u;
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>::exponent_nan:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- return;
- }
- if (v == 0)
- {
- bool s = u.sign();
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
- res.sign() = s;
- return;
- }
- // We can scale u and v so that both are integers, then perform integer
- // division to obtain quotient q and remainder r, such that:
- //
- // q * v + r = u
- //
- // and hense:
- //
- // q + r/v = u/v
- //
- // From this, assuming q has "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count" cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count, we only need to determine whether
- // r/v is less than, equal to, or greater than 0.5 to determine rounding -
- // this we can do with a shift and comparison.
- //
- // We can set the exponent and sign of the result up front:
- //
- std::ptrdiff_t gb = static_cast<std::ptrdiff_t>(msb(v));
- res.exponent() = u.exponent() - static_cast<Exponent>(gb) - static_cast<Exponent>(1);
- res.sign() = u.sign();
- //
- // Now get the quotient and remainder:
- //
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type t(u.bits()), q, r;
- eval_left_shift(t, static_cast<double_limb_type>(gb + 1));
- eval_qr(t, number<typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type>::canonical_value(v), q, r);
- //
- // We now have either "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count" or "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count+1" significant cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count in q.
- //
- constexpr unsigned limb_bits = sizeof(limb_type) * CHAR_BIT;
- if (eval_bit_test(q, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count))
- {
- //
- // OK we have cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count+1 cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count, so we already have rounding info,
- // we just need to changes things if the last bit is 1 and the
- // remainder is non-zero (ie we do not have a tie).
- //
- BOOST_MP_ASSERT((eval_msb(q) == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count));
- if ((q.limbs()[0] & 1u) && eval_get_sign(r))
- {
- eval_increment(q);
- }
- }
- else
- {
- //
- // We have exactly "cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count" cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count in q.
- // Get rounding info, which we can get by comparing 2r with v.
- // We want to call copy_and_round to handle rounding and general cleanup,
- // so we'll left shift q and add some fake cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count on the end to represent
- // how we'll be rounding.
- //
- using local_exponent_type = typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type;
- BOOST_MP_ASSERT((eval_msb(q) == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1));
- constexpr unsigned lshift = cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count < limb_bits ? 2 : limb_bits;
- eval_left_shift(q, lshift);
- res.exponent() -= static_cast<local_exponent_type>(lshift);
- eval_left_shift(r, 1u);
- int c = r.compare(number<typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type>::canonical_value(v));
- if (c == 0)
- q.limbs()[0] |= static_cast<limb_type>(1u) << (lshift - 1);
- else if (c > 0)
- q.limbs()[0] |= (static_cast<limb_type>(1u) << (lshift - 1)) + static_cast<limb_type>(1u);
- }
- copy_and_round(res, q);
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class U>
- inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<U>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const U& v)
- {
- eval_divide(res, res, v);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2, class S>
- inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res,
- const cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2>& u, const S& v)
- {
- using ui_type = typename boost::multiprecision::detail::make_unsigned<S>::type;
- eval_divide(res, u, static_cast<ui_type>(boost::multiprecision::detail::unsigned_abs(v)));
- if (v < 0)
- res.negate();
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class S>
- inline typename std::enable_if<boost::multiprecision::detail::is_signed<S>::value && boost::multiprecision::detail::is_integral<S>::value>::type eval_divide(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const S& v)
- {
- eval_divide(res, res, v);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline int eval_get_sign(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- return arg.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero ? 0 : arg.sign() ? -1 : 1;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline bool eval_is_zero(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- return arg.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline bool eval_eq(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& a, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& b)
- {
- if (a.exponent() == b.exponent())
- {
- if (a.exponent() == cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero)
- return true;
- return (a.sign() == b.sign()) && (a.bits().compare(b.bits()) == 0) && (a.exponent() != cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan);
- }
- return false;
- }
- template <class I, unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void convert_to_signed_int(I* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- static constexpr int digits = std::numeric_limits<I>::is_specialized ? std::numeric_limits<I>::digits : sizeof(I) * CHAR_BIT - 1;
- static constexpr I max_val = std::numeric_limits<I>::is_specialized ? (std::numeric_limits<I>::max)() : (((I(1) << (sizeof(I) * CHAR_BIT - 2)) - 1) << 1) + 1;
- static constexpr I min_val = std::numeric_limits<I>::is_specialized ? (std::numeric_limits<I>::min)() : -max_val - 1;
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- *res = 0;
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- BOOST_MP_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer."));
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- *res = max_val;
- if (arg.sign())
- *res = -*res;
- return;
- }
- using shift_type = typename std::conditional<sizeof(typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type) < sizeof(int), int, typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type>::type;
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::rep_type man(arg.bits());
- shift_type shift = (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 - arg.exponent();
- if (shift > (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1)
- {
- *res = 0;
- return;
- }
- if (arg.sign() && (arg.compare(min_val) <= 0))
- {
- *res = min_val;
- return;
- }
- else if (!arg.sign() && (arg.compare(max_val) >= 0))
- {
- *res = max_val;
- return;
- }
- if (shift < 0)
- {
- if (static_cast<int>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - static_cast<int>(shift) <= digits)
- {
- // We have more bits in long_long_type than the float, so it's OK to left shift:
- eval_convert_to(res, man);
- *res <<= -shift;
- }
- else
- {
- *res = (std::numeric_limits<I>::max)();
- return;
- }
- }
- else
- {
- eval_right_shift(man, static_cast<double_limb_type>(shift));
- eval_convert_to(res, man);
- }
- if (arg.sign())
- {
- *res = -*res;
- }
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_convert_to(long long* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- convert_to_signed_int(res, arg);
- }
- #ifdef BOOST_HAS_INT128
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_convert_to(int128_type* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- convert_to_signed_int(res, arg);
- }
- #endif
- template <class I, unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void convert_to_unsigned_int(I* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- static constexpr int digits = std::numeric_limits<I>::is_specialized ? std::numeric_limits<I>::digits : sizeof(I) * CHAR_BIT;
- static constexpr I max_val = std::numeric_limits<I>::is_specialized ? (std::numeric_limits<I>::max)() : ~static_cast<I>(0);
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- *res = 0;
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- BOOST_MP_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer."));
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- *res = max_val;
- return;
- }
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::rep_type man(arg.bits());
- using shift_type = typename std::conditional<sizeof(typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type) < sizeof(int), int, typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type>::type;
- shift_type shift = (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 - arg.exponent();
- if (shift > (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1)
- {
- *res = 0;
- return;
- }
- else if (shift < 0)
- {
- if (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - shift <= digits)
- {
- // We have more bits in ulong_long_type than the float, so it's OK to left shift:
- eval_convert_to(res, man);
- *res <<= -shift;
- return;
- }
- *res = max_val;
- return;
- }
- eval_right_shift(man, shift);
- eval_convert_to(res, man);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_convert_to(unsigned long long* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- convert_to_unsigned_int(res, arg);
- }
- #ifdef BOOST_HAS_INT128
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_convert_to(uint128_type* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- convert_to_unsigned_int(res, arg);
- }
- #endif
- template <class Float, unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline typename std::enable_if<std::is_floating_point<Float>::value>::type eval_convert_to(Float* res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& original_arg)
- {
- using conv_type = cpp_bin_float<std::numeric_limits<Float>::digits, digit_base_2, void, Exponent, MinE, MaxE>;
- using common_exp_type = typename std::common_type<typename conv_type::exponent_type, int>::type;
- static constexpr int float_digits = boost::multiprecision::detail::is_float128<Float>::value ? 113 : std::numeric_limits<Float>::digits;
- BOOST_MP_FLOAT128_USING using std::ldexp;
- //
- // Special cases first:
- //
- switch (original_arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- *res = 0;
- if (original_arg.sign())
- *res = -*res;
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- BOOST_IF_CONSTEXPR(boost::multiprecision::detail::is_float128<Float>::value)
- {
- *res = static_cast<Float>(std::numeric_limits<double>::quiet_NaN());
- }
- else
- {
- *res = std::numeric_limits<Float>::quiet_NaN();
- }
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- BOOST_IF_CONSTEXPR(boost::multiprecision::detail::is_float128<Float>::value)
- {
- *res = static_cast<Float>((std::numeric_limits<double>::infinity)());
- }
- else
- {
- *res = (std::numeric_limits<Float>::infinity)();
- }
- if (original_arg.sign())
- *res = -*res;
- return;
- }
- //
- // Check for super large exponent that must be converted to infinity:
- //
- if (original_arg.exponent() > (boost::multiprecision::detail::is_float128<Float>::value ? 16384 : std::numeric_limits<Float>::max_exponent))
- {
- BOOST_IF_CONSTEXPR(boost::multiprecision::detail::is_float128<Float>::value)
- {
- *res = static_cast<Float>(std::numeric_limits<double>::infinity());
- }
- else
- {
- *res = std::numeric_limits<Float>::has_infinity ? std::numeric_limits<Float>::infinity() : (std::numeric_limits<Float>::max)();
- }
- if (original_arg.sign())
- *res = -*res;
- return;
- }
- //
- // Figure out how many digits we will have in our result,
- // allowing for a possibly denormalized result:
- //
- common_exp_type digits_to_round_to = float_digits;
- if (original_arg.exponent() < std::numeric_limits<Float>::min_exponent - 1)
- {
- common_exp_type diff = original_arg.exponent();
- diff -= boost::multiprecision::detail::is_float128<Float>::value ? -16382 : std::numeric_limits<Float>::min_exponent - 1;
- digits_to_round_to += diff;
- }
- if (digits_to_round_to < 0)
- {
- // Result must be zero:
- *res = 0;
- if (original_arg.sign())
- *res = -*res;
- return;
- }
- //
- // Perform rounding first, then afterwards extract the digits:
- //
- cpp_bin_float<static_cast<unsigned>(float_digits), digit_base_2, Allocator, Exponent, MinE, MaxE> arg;
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::rep_type bits(original_arg.bits());
- arg.exponent() = original_arg.exponent();
- copy_and_round(arg, bits, (std::ptrdiff_t)digits_to_round_to);
- common_exp_type e = arg.exponent();
- e -= static_cast<common_exp_type>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - 1;
- constexpr std::size_t limbs_needed = static_cast<std::size_t>(float_digits) / (sizeof(*arg.bits().limbs()) * CHAR_BIT) + (static_cast<std::size_t>(float_digits) % (sizeof(*arg.bits().limbs()) * CHAR_BIT) ? 1 : 0);
- std::size_t first_limb_needed = arg.bits().size() - limbs_needed;
- *res = 0;
- e += static_cast<common_exp_type>(first_limb_needed * sizeof(*arg.bits().limbs()) * CHAR_BIT);
- while (first_limb_needed < arg.bits().size())
- {
- *res += ldexp(static_cast<Float>(arg.bits().limbs()[first_limb_needed]), static_cast<int>(e));
- ++first_limb_needed;
- e += static_cast<common_exp_type>(sizeof(*arg.bits().limbs()) * CHAR_BIT);
- }
- if (original_arg.sign())
- *res = -*res;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_frexp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg, Exponent* e)
- {
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- *e = 0;
- res = arg;
- return;
- }
- res = arg;
- *e = arg.exponent() + 1;
- res.exponent() = -1;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class I>
- inline void eval_frexp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg, I* pe)
- {
- Exponent e;
- eval_frexp(res, arg, &e);
- if ((e > (std::numeric_limits<I>::max)()) || (e < (std::numeric_limits<I>::min)()))
- {
- BOOST_MP_THROW_EXCEPTION(std::runtime_error("Exponent was outside of the range of the argument type to frexp."));
- }
- *pe = static_cast<I>(e);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_ldexp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg, Exponent e)
- {
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- res = arg;
- return;
- }
- if ((e > 0) && (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent - e < arg.exponent()))
- {
- // Overflow:
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
- res.sign() = arg.sign();
- }
- else if ((e < 0) && (cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent - e > arg.exponent()))
- {
- // Underflow:
- res = limb_type(0);
- }
- else
- {
- res = arg;
- res.exponent() += e;
- }
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class I>
- inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<I>::value>::type eval_ldexp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg, I e)
- {
- using si_type = typename boost::multiprecision::detail::make_signed<I>::type;
- if (e > static_cast<I>((std::numeric_limits<si_type>::max)()))
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
- else
- eval_ldexp(res, arg, static_cast<si_type>(e));
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class I>
- inline typename std::enable_if<boost::multiprecision::detail::is_signed<I>::value && boost::multiprecision::detail::is_integral<I>::value>::type eval_ldexp(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg, I e)
- {
- if ((e > (std::numeric_limits<Exponent>::max)()) || (e < (std::numeric_limits<Exponent>::min)()))
- {
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::infinity().backend();
- if (e < 0)
- res.negate();
- }
- else
- eval_ldexp(res, arg, static_cast<Exponent>(e));
- }
- /*
- * Sign manipulation
- */
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- unsigned Digits2, digit_base_type DigitBase2, class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- inline void eval_abs(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits2, DigitBase2, Allocator2, Exponent2, MinE2, MaxE2>& arg)
- {
- res = arg;
- res.sign() = false;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_abs(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- res = arg;
- res.sign() = false;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE,
- unsigned Digits2, digit_base_type DigitBase2, class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- inline void eval_fabs(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits2, DigitBase2, Allocator2, Exponent2, MinE2, MaxE2>& arg)
- {
- res = arg;
- res.sign() = false;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_fabs(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- res = arg;
- res.sign() = false;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline int eval_fpclassify(const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- return FP_ZERO;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- return FP_INFINITE;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- return FP_NAN;
- }
- return FP_NORMAL;
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_sqrt(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- using default_ops::eval_bit_test;
- using default_ops::eval_increment;
- using default_ops::eval_integer_sqrt;
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- errno = EDOM;
- // fallthrough...
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- res = arg;
- return;
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- if (arg.sign())
- {
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- errno = EDOM;
- }
- else
- res = arg;
- return;
- }
- if (arg.sign())
- {
- res = std::numeric_limits<number<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > >::quiet_NaN().backend();
- errno = EDOM;
- return;
- }
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::double_rep_type t(arg.bits()), r, s;
- eval_left_shift(t, arg.exponent() & 1 ? cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count : cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1);
- eval_integer_sqrt(s, r, t);
- if (!eval_bit_test(s, cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count))
- {
- // We have exactly the right number of cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count in the result, round as required:
- if (s.compare(r) < 0)
- {
- eval_increment(s);
- }
- }
- typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type ae = arg.exponent();
- res.exponent() = ae / 2;
- res.sign() = false;
- if ((ae & 1) && (ae < 0))
- --res.exponent();
- copy_and_round(res, s);
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_floor(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- using default_ops::eval_increment;
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- errno = EDOM;
- // fallthrough...
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- res = arg;
- return;
- }
- using shift_type = typename std::conditional<sizeof(typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type) < sizeof(int), int, typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type>::type;
- shift_type shift =
- (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - arg.exponent() - 1;
- if ((arg.exponent() > (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent) || (shift <= 0))
- {
- // Either arg is already an integer, or a special value:
- res = arg;
- return;
- }
- if (shift >= (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count)
- {
- res = static_cast<signed_limb_type>(arg.sign() ? -1 : 0);
- return;
- }
- bool fractional = (shift_type)eval_lsb(arg.bits()) < shift;
- res = arg;
- eval_right_shift(res.bits(), static_cast<double_limb_type>(shift));
- if (fractional && res.sign())
- {
- eval_increment(res.bits());
- const std::ptrdiff_t shift_check =
- static_cast<std::ptrdiff_t>(static_cast<std::ptrdiff_t>(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count) - 1 - static_cast<std::ptrdiff_t>(shift));
- if (static_cast<std::ptrdiff_t>(eval_msb(res.bits())) != shift_check)
- {
- // Must have extended result by one bit in the increment:
- --shift;
- ++res.exponent();
- }
- }
- eval_left_shift(res.bits(), static_cast<double_limb_type>(shift));
- }
- template <unsigned Digits, digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE>
- inline void eval_ceil(cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& res, const cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>& arg)
- {
- using default_ops::eval_increment;
- switch (arg.exponent())
- {
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity:
- errno = EDOM;
- // fallthrough...
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_zero:
- case cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan:
- res = arg;
- return;
- }
- using shift_type = typename std::conditional<sizeof(typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type) < sizeof(int), int, typename cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type>::type;
- shift_type shift = (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - arg.exponent() - 1;
- if ((arg.exponent() > (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent) || (shift <= 0))
- {
- // Either arg is already an integer, or a special value:
- res = arg;
- return;
- }
- if (shift >= (shift_type)cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count)
- {
- bool s = arg.sign(); // takes care of signed zeros
- res = static_cast<signed_limb_type>(arg.sign() ? 0 : 1);
- res.sign() = s;
- return;
- }
- bool fractional = (shift_type)eval_lsb(arg.bits()) < shift;
- res = arg;
- eval_right_shift(res.bits(), shift);
- if (fractional && !res.sign())
- {
- eval_increment(res.bits());
- if ((std::ptrdiff_t)eval_msb(res.bits()) != cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1 - shift)
- {
- // Must have extended result by one bit in the increment:
- --shift;
- ++res.exponent();
- }
- }
- eval_left_shift(res.bits(), shift);
- }
- template <unsigned D1, backends::digit_base_type B1, class A1, class E1, E1 M1, E1 M2>
- int eval_signbit(const cpp_bin_float<D1, B1, A1, E1, M1, M2>& val)
- {
- return val.sign();
- }
- template <unsigned D1, backends::digit_base_type B1, class A1, class E1, E1 M1, E1 M2>
- inline std::size_t hash_value(const cpp_bin_float<D1, B1, A1, E1, M1, M2>& val)
- {
- std::size_t result = hash_value(val.bits());
- boost::multiprecision::detail::hash_combine(result, val.exponent(), val.sign());
- return result;
- }
- } // namespace backends
- namespace detail {
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinExponent, Exponent MaxExponent>
- struct transcendental_reduction_type<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> >
- {
- //
- // The type used for trigonometric reduction needs 3 times the precision of the base type.
- // This is double the precision of the original type, plus the largest exponent supported.
- // As a practical measure the largest argument supported is 1/eps, as supporting larger
- // arguments requires the division of argument by PI/2 to also be done at higher precision,
- // otherwise the result (an integer) can not be represented exactly.
- //
- // See ARGUMENT REDUCTION FOR HUGE ARGUMENTS. K C Ng.
- //
- using type = boost::multiprecision::backends::cpp_bin_float<
- boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent>::bit_count * 3,
- boost::multiprecision::backends::digit_base_2,
- Allocator, Exponent, MinExponent, MaxExponent>;
- };
- #ifdef BOOST_HAS_INT128
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinExponent, Exponent MaxExponent>
- struct is_convertible_arithmetic<int128_type, boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> > : public std::true_type
- {};
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinExponent, Exponent MaxExponent>
- struct is_convertible_arithmetic<uint128_type, boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> > : public std::true_type
- {};
- #endif
- } // namespace detail
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Exponent, Exponent MinE, Exponent MaxE, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
- inline boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>
- copysign BOOST_PREVENT_MACRO_SUBSTITUTION(
- const boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>& a,
- const boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>& b)
- {
- boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> res(a);
- res.backend().sign() = b.backend().sign();
- return res;
- }
- template <unsigned Digits, backends::digit_base_type DigitBase, class Exponent, Exponent MinE, Exponent MaxE, class Allocator>
- struct number_category<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE> > : public std::integral_constant<int, boost::multiprecision::number_kind_floating_point>
- {};
- template <unsigned Digits, backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, class Allocator2, class Exponent2, Exponent MinE2, Exponent MaxE2>
- struct is_equivalent_number_type<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, cpp_bin_float<Digits, DigitBase, Allocator2, Exponent2, MinE2, MaxE2> >
- : public std::integral_constant<bool, true> {};
- } // namespace multiprecision
- namespace math {
- using boost::multiprecision::copysign;
- using boost::multiprecision::signbit;
- } // namespace math
- } // namespace boost
- #include <boost/multiprecision/cpp_bin_float/io.hpp>
- #include <boost/multiprecision/cpp_bin_float/transcendental.hpp>
- namespace std {
- //
- // numeric_limits [partial] specializations for the types declared in this header:
- //
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- class numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >
- {
- using number_type = boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates>;
- private:
- //
- // Functions to calculate cached values stored in static values:
- //
- static number_type get_min()
- {
- using ui_type = typename std::tuple_element<0, typename number_type::backend_type::unsigned_types>::type;
- number_type value(ui_type(1u));
- value.backend().exponent() = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
- return value;
- }
- #ifdef BOOST_MSVC
- #pragma warning(push)
- #pragma warning(disable : 4127) // conditional expression is constant
- #endif
- static number_type get_max()
- {
- number_type value;
- BOOST_IF_CONSTEXPR(std::is_void<Allocator>::value)
- eval_complement(value.backend().bits(), value.backend().bits());
- else
- {
- // We jump through hoops here using the backend type directly just to keep VC12 happy
- // (ie compiler workaround, for very strange compiler bug):
- using boost::multiprecision::default_ops::eval_add;
- using boost::multiprecision::default_ops::eval_decrement;
- using boost::multiprecision::default_ops::eval_left_shift;
- using int_backend_type = typename number_type::backend_type::rep_type;
- using ui_type = typename std::tuple_element<0, typename int_backend_type::unsigned_types>::type;
- int_backend_type i;
- i = ui_type(1u);
- eval_left_shift(i, boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count - 1);
- int_backend_type j(i);
- eval_decrement(i);
- eval_add(j, i);
- value.backend().bits() = j;
- }
- value.backend().exponent() = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
- return value;
- }
- #ifdef BOOST_MSVC
- #pragma warning(pop)
- #endif
- static number_type get_epsilon()
- {
- using ui_type = typename std::tuple_element<0, typename number_type::backend_type::unsigned_types>::type;
- number_type value(ui_type(1u));
- return ldexp(value, 1 - static_cast<int>(digits));
- }
- // What value should this be????
- static number_type get_round_error()
- {
- // returns 0.5
- return ldexp(number_type(1u), -1);
- }
- static number_type get_infinity()
- {
- number_type value;
- value.backend().exponent() = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_infinity;
- return value;
- }
- static number_type get_quiet_NaN()
- {
- number_type value;
- value.backend().exponent() = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_nan;
- return value;
- }
- public:
- static constexpr bool is_specialized = true;
- static number_type(min)()
- {
- // C++11 thread safe static initialization:
- static number_type value = get_min();
- return value;
- }
- static number_type(max)()
- {
- // C++11 thread safe static initialization:
- static number_type value = get_max();
- return value;
- }
- static constexpr number_type lowest()
- {
- return -(max)();
- }
- static constexpr int digits = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::bit_count;
- static constexpr int digits10 = boost::multiprecision::detail::calc_digits10<static_cast<unsigned>(digits)>::value;
- // Is this really correct???
- static constexpr int max_digits10 = boost::multiprecision::detail::calc_max_digits10<static_cast<unsigned>(digits)>::value;
- static constexpr bool is_signed = true;
- static constexpr bool is_integer = false;
- static constexpr bool is_exact = false;
- static constexpr int radix = 2;
- static number_type epsilon()
- {
- // C++11 thread safe static initialization:
- static number_type value = get_epsilon();
- return value;
- }
- // What value should this be????
- static number_type round_error()
- {
- // returns 0.5
- // C++11 thread safe static initialization:
- static number_type value = get_round_error();
- return value;
- }
- static constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type min_exponent = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::min_exponent;
- static constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type min_exponent10 = (min_exponent / 1000) * 301L;
- static constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type max_exponent = boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::max_exponent;
- static constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type max_exponent10 = (max_exponent / 1000) * 301L;
- static constexpr bool has_infinity = true;
- static constexpr bool has_quiet_NaN = true;
- static constexpr bool has_signaling_NaN = false;
- static constexpr float_denorm_style has_denorm = denorm_absent;
- static constexpr bool has_denorm_loss = false;
- static number_type infinity()
- {
- // C++11 thread safe static initialization:
- static number_type value = get_infinity();
- return value;
- }
- static number_type quiet_NaN()
- {
- // C++11 thread safe static initialization:
- static number_type value = get_quiet_NaN();
- return value;
- }
- static constexpr number_type signaling_NaN()
- {
- return number_type(0);
- }
- static constexpr number_type denorm_min() { return get_min(); }
- static constexpr bool is_iec559 = false;
- static constexpr bool is_bounded = true;
- static constexpr bool is_modulo = false;
- static constexpr bool traps = true;
- static constexpr bool tinyness_before = false;
- static constexpr float_round_style round_style = round_to_nearest;
- };
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::digits;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::digits10;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::max_digits10;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::is_signed;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::is_integer;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::is_exact;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::radix;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::min_exponent;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::min_exponent10;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::max_exponent;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr typename boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>::exponent_type numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::max_exponent10;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::has_infinity;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::has_quiet_NaN;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::has_signaling_NaN;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::has_denorm;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::has_denorm_loss;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::is_iec559;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::is_bounded;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::is_modulo;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::traps;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::tinyness_before;
- template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
- constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >::round_style;
- } // namespace std
- #endif
|