Chris@102: /////////////////////////////////////////////////////////////// Chris@102: // Copyright 2013 John Maddock. Distributed under the Boost Chris@102: // Software License, Version 1.0. (See accompanying file Chris@102: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ Chris@102: Chris@102: #ifndef BOOST_MATH_CPP_BIN_FLOAT_HPP Chris@102: #define BOOST_MATH_CPP_BIN_FLOAT_HPP Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: namespace boost{ namespace multiprecision{ namespace backends{ Chris@102: Chris@102: enum digit_base_type Chris@102: { Chris@102: digit_base_2 = 2, Chris@102: digit_base_10 = 10 Chris@102: }; Chris@102: Chris@102: #ifdef BOOST_MSVC Chris@102: #pragma warning(push) Chris@102: #pragma warning(disable:4522) // multiple assignment operators specified Chris@102: #endif Chris@102: Chris@102: namespace detail{ Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value, bool>::type is_negative(U) { return false; } Chris@102: template Chris@102: inline typename disable_if_c::value, bool>::type is_negative(S s) { return s < 0; } Chris@102: Chris@102: } Chris@102: Chris@102: template Chris@102: class cpp_bin_float Chris@102: { Chris@102: public: Chris@102: static const unsigned bit_count = DigitBase == digit_base_2 ? Digits : (Digits * 1000uL) / 301uL + ((Digits * 1000uL) % 301 ? 2u : 1u); Chris@102: typedef cpp_int_backend::value ? bit_count : 0, bit_count, is_void::value ? unsigned_magnitude : signed_magnitude, unchecked, Allocator> rep_type; Chris@102: typedef cpp_int_backend::value ? 2 * bit_count : 0, 2 * bit_count, is_void::value ? unsigned_magnitude : signed_magnitude, unchecked, Allocator> double_rep_type; Chris@102: Chris@102: typedef typename rep_type::signed_types signed_types; Chris@102: typedef typename rep_type::unsigned_types unsigned_types; Chris@102: typedef boost::mpl::list float_types; Chris@102: typedef Exponent exponent_type; Chris@102: Chris@102: static const exponent_type max_exponent_limit = boost::integer_traits::const_max - 2 * static_cast(bit_count); Chris@102: static const exponent_type min_exponent_limit = boost::integer_traits::const_min + 2 * static_cast(bit_count); Chris@102: Chris@102: BOOST_STATIC_ASSERT_MSG(MinExponent >= min_exponent_limit, "Template parameter MinExponent is too negative for our internal logic to function correctly, sorry!"); Chris@102: BOOST_STATIC_ASSERT_MSG(MaxExponent <= max_exponent_limit, "Template parameter MaxExponent is too large for our internal logic to function correctly, sorry!"); Chris@102: BOOST_STATIC_ASSERT_MSG(MinExponent <= 0, "Template parameter MinExponent can not be positive!"); Chris@102: BOOST_STATIC_ASSERT_MSG(MaxExponent >= 0, "Template parameter MaxExponent can not be negative!"); Chris@102: Chris@102: static const exponent_type max_exponent = MaxExponent == 0 ? max_exponent_limit : MaxExponent; Chris@102: static const exponent_type min_exponent = MinExponent == 0 ? min_exponent_limit : MinExponent; Chris@102: Chris@102: static const exponent_type exponent_zero = max_exponent + 1; Chris@102: static const exponent_type exponent_infinity = max_exponent + 2; Chris@102: static const exponent_type exponent_nan = max_exponent + 3; Chris@102: Chris@102: private: Chris@102: Chris@102: rep_type m_data; Chris@102: exponent_type m_exponent; Chris@102: bool m_sign; Chris@102: public: Chris@102: cpp_bin_float() BOOST_NOEXCEPT_IF(noexcept(rep_type())) : m_data(), m_exponent(exponent_nan), m_sign(false) {} Chris@102: Chris@102: cpp_bin_float(const cpp_bin_float &o) BOOST_NOEXCEPT_IF(noexcept(rep_type(std::declval()))) Chris@102: : m_data(o.m_data), m_exponent(o.m_exponent), m_sign(o.m_sign) {} Chris@102: Chris@102: template Chris@102: cpp_bin_float(const cpp_bin_float &o, typename boost::enable_if_c<(bit_count >= cpp_bin_float::bit_count)>::type const* = 0) Chris@102: : m_exponent(o.exponent()), m_sign(o.sign()) Chris@102: { Chris@102: typename cpp_bin_float::rep_type b(o.bits()); Chris@102: this->sign() = o.sign(); Chris@102: this->exponent() = o.exponent() + (int)bit_count - (int)cpp_bin_float::bit_count; Chris@102: copy_and_round(*this, b); Chris@102: } Chris@102: Chris@102: template Chris@102: explicit cpp_bin_float(const cpp_bin_float &o, typename boost::disable_if_c<(bit_count >= cpp_bin_float::bit_count)>::type const* = 0) Chris@102: : m_exponent(o.exponent()), m_sign(o.sign()) Chris@102: { Chris@102: typename cpp_bin_float::rep_type b(o.bits()); Chris@102: this->sign() = o.sign(); Chris@102: this->exponent() = o.exponent() - (int)(cpp_bin_float::bit_count - bit_count); Chris@102: copy_and_round(*this, b); Chris@102: } Chris@102: Chris@102: template Chris@102: cpp_bin_float(const Float& f, Chris@102: typename boost::enable_if_c< Chris@102: (number_category::value == number_kind_floating_point) Chris@102: && (std::numeric_limits::digits <= (int)bit_count) Chris@102: && (std::numeric_limits::radix == 2) Chris@102: >::type const* = 0) Chris@102: : m_data(), m_exponent(0), m_sign(false) Chris@102: { Chris@102: this->assign_float(f); Chris@102: } Chris@102: Chris@102: cpp_bin_float& operator=(const cpp_bin_float &o) BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval())) Chris@102: { Chris@102: m_data = o.m_data; Chris@102: m_exponent = o.m_exponent; Chris@102: m_sign = o.m_sign; Chris@102: return *this; Chris@102: } Chris@102: Chris@102: template Chris@102: cpp_bin_float& operator=(const cpp_bin_float &o) Chris@102: { Chris@102: typename cpp_bin_float::rep_type b(o.bits()); Chris@102: this->exponent() = o.exponent() + (int)bit_count - (int)cpp_bin_float::bit_count; Chris@102: this->sign() = o.sign(); Chris@102: copy_and_round(*this, b); Chris@102: return *this; Chris@102: } Chris@102: Chris@102: template Chris@102: typename boost::enable_if_c< Chris@102: (number_category::value == number_kind_floating_point) Chris@102: && (std::numeric_limits::digits <= (int)bit_count) Chris@102: && (std::numeric_limits::radix == 2), cpp_bin_float&>::type operator=(const Float& f) Chris@102: { Chris@102: return assign_float(f); Chris@102: } Chris@102: Chris@102: template Chris@102: typename boost::enable_if_c::value, cpp_bin_float&>::type assign_float(Float f) Chris@102: { Chris@102: BOOST_MATH_STD_USING Chris@102: using default_ops::eval_add; Chris@102: typedef typename boost::multiprecision::detail::canonical::type bf_int_type; Chris@102: Chris@102: switch((boost::math::fpclassify)(f)) Chris@102: { Chris@102: case FP_ZERO: Chris@102: m_data = limb_type(0); Chris@102: m_sign = false; Chris@102: m_exponent = exponent_zero; Chris@102: return *this; Chris@102: case FP_NAN: Chris@102: m_data = limb_type(0); Chris@102: m_sign = false; Chris@102: m_exponent = exponent_nan; Chris@102: return *this; Chris@102: case FP_INFINITE: Chris@102: m_data = limb_type(0); Chris@102: m_sign = false; Chris@102: m_exponent = exponent_infinity; Chris@102: return *this; Chris@102: } Chris@102: if(f < 0) Chris@102: { Chris@102: *this = -f; Chris@102: this->negate(); Chris@102: return *this; Chris@102: } Chris@102: Chris@102: typedef typename mpl::front::type ui_type; Chris@102: m_data = static_cast(0u); Chris@102: m_sign = false; Chris@102: m_exponent = 0; Chris@102: Chris@102: static const int bits = sizeof(int) * CHAR_BIT - 1; Chris@102: int e; Chris@102: f = frexp(f, &e); Chris@102: while(f) Chris@102: { Chris@102: f = ldexp(f, bits); Chris@102: e -= bits; Chris@102: #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS Chris@102: int ipart = itrunc(f); Chris@102: #else Chris@102: int ipart = static_cast(f); Chris@102: #endif Chris@102: f -= ipart; Chris@102: m_exponent += bits; Chris@102: cpp_bin_float t; Chris@102: t = static_cast(ipart); Chris@102: eval_add(*this, t); Chris@102: } Chris@102: m_exponent += static_cast(e); Chris@102: return *this; Chris@102: } Chris@102: Chris@102: template Chris@102: typename boost::enable_if_c< Chris@102: (number_category::value == number_kind_floating_point) Chris@102: && !is_floating_point::value Chris@102: /*&& (std::numeric_limits >::radix == 2)*/, Chris@102: cpp_bin_float&>::type assign_float(Float f) Chris@102: { Chris@102: BOOST_MATH_STD_USING Chris@102: using default_ops::eval_add; Chris@102: using default_ops::eval_get_sign; Chris@102: using default_ops::eval_convert_to; Chris@102: using default_ops::eval_subtract; Chris@102: Chris@102: typedef typename boost::multiprecision::detail::canonical::type f_int_type; Chris@102: typedef typename boost::multiprecision::detail::canonical::type bf_int_type; Chris@102: Chris@102: switch(eval_fpclassify(f)) Chris@102: { Chris@102: case FP_ZERO: Chris@102: m_data = limb_type(0); Chris@102: m_sign = false; Chris@102: m_exponent = exponent_zero; Chris@102: return *this; Chris@102: case FP_NAN: Chris@102: m_data = limb_type(0); Chris@102: m_sign = false; Chris@102: m_exponent = exponent_nan; Chris@102: return *this; Chris@102: case FP_INFINITE: Chris@102: m_data = limb_type(0); Chris@102: m_sign = false; Chris@102: m_exponent = exponent_infinity; Chris@102: return *this; Chris@102: } Chris@102: if(eval_get_sign(f) < 0) Chris@102: { Chris@102: f.negate(); Chris@102: *this = f; Chris@102: this->negate(); Chris@102: return *this; Chris@102: } Chris@102: Chris@102: typedef typename mpl::front::type ui_type; Chris@102: m_data = static_cast(0u); Chris@102: m_sign = false; Chris@102: m_exponent = 0; Chris@102: Chris@102: static const int bits = sizeof(int) * CHAR_BIT - 1; Chris@102: int e; Chris@102: eval_frexp(f, f, &e); Chris@102: while(eval_get_sign(f) != 0) Chris@102: { Chris@102: eval_ldexp(f, f, bits); Chris@102: e -= bits; Chris@102: int ipart; Chris@102: eval_convert_to(&ipart, f); Chris@102: eval_subtract(f, static_cast(ipart)); Chris@102: m_exponent += bits; Chris@102: eval_add(*this, static_cast(ipart)); Chris@102: } Chris@102: m_exponent += e; Chris@102: if(m_exponent > max_exponent) Chris@102: m_exponent = exponent_infinity; Chris@102: if(m_exponent < min_exponent) Chris@102: { Chris@102: m_data = limb_type(0u); Chris@102: m_exponent = exponent_zero; Chris@102: m_sign = false; Chris@102: } Chris@102: else if(eval_get_sign(m_data) == 0) Chris@102: { Chris@102: m_exponent = exponent_zero; Chris@102: m_sign = false; Chris@102: } Chris@102: return *this; Chris@102: } Chris@102: Chris@102: template Chris@102: typename boost::enable_if, cpp_bin_float&>::type operator=(const I& i) Chris@102: { Chris@102: using default_ops::eval_bit_test; Chris@102: if(!i) Chris@102: { Chris@102: m_data = static_cast(0); Chris@102: m_exponent = exponent_zero; Chris@102: m_sign = false; Chris@102: } Chris@102: else Chris@102: { Chris@102: typedef typename make_unsigned::type ui_type; Chris@102: ui_type fi = static_cast(boost::multiprecision::detail::unsigned_abs(i)); Chris@102: typedef typename boost::multiprecision::detail::canonical::type ar_type; Chris@102: m_data = static_cast(fi); Chris@102: unsigned shift = msb(fi); Chris@102: if(shift >= bit_count) Chris@102: { Chris@102: m_exponent = static_cast(shift); Chris@102: m_data = static_cast(fi >> (shift + 1 - bit_count)); Chris@102: } Chris@102: else Chris@102: { Chris@102: m_exponent = static_cast(shift); Chris@102: eval_left_shift(m_data, bit_count - shift - 1); Chris@102: } Chris@102: BOOST_ASSERT(eval_bit_test(m_data, bit_count-1)); Chris@102: m_sign = detail::is_negative(i); Chris@102: } Chris@102: return *this; Chris@102: } Chris@102: Chris@102: cpp_bin_float& operator=(const char *s); Chris@102: Chris@102: void swap(cpp_bin_float &o) BOOST_NOEXCEPT Chris@102: { Chris@102: m_data.swap(o.m_data); Chris@102: std::swap(m_exponent, o.m_exponent); Chris@102: std::swap(m_sign, o.m_sign); Chris@102: } Chris@102: Chris@102: std::string str(std::streamsize dig, std::ios_base::fmtflags f) const; Chris@102: Chris@102: void negate() Chris@102: { Chris@102: if((m_exponent != exponent_zero) && (m_exponent != exponent_nan)) Chris@102: m_sign = !m_sign; Chris@102: } Chris@102: Chris@102: int compare(const cpp_bin_float &o) const BOOST_NOEXCEPT Chris@102: { Chris@102: if(m_sign != o.m_sign) Chris@102: return m_sign ? -1 : 1; Chris@102: int result; Chris@102: if(m_exponent == exponent_nan) Chris@102: return -1; Chris@102: else if(m_exponent != o.m_exponent) Chris@102: { Chris@102: if(m_exponent == exponent_zero) Chris@102: result = -1; Chris@102: else if(o.m_exponent == exponent_zero) Chris@102: result = 1; Chris@102: else Chris@102: result = m_exponent > o.m_exponent ? 1 : -1; Chris@102: } Chris@102: else Chris@102: result = m_data.compare(o.m_data); Chris@102: if(m_sign) Chris@102: result = -result; Chris@102: return result; Chris@102: } Chris@102: template Chris@102: int compare(const A& o) const BOOST_NOEXCEPT Chris@102: { Chris@102: cpp_bin_float b; Chris@102: b = o; Chris@102: return compare(b); Chris@102: } Chris@102: Chris@102: rep_type& bits() { return m_data; } Chris@102: const rep_type& bits()const { return m_data; } Chris@102: exponent_type& exponent() { return m_exponent; } Chris@102: const exponent_type& exponent()const { return m_exponent; } Chris@102: bool& sign() { return m_sign; } Chris@102: const bool& sign()const { return m_sign; } Chris@102: void check_invariants() Chris@102: { Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_is_zero; Chris@102: if((m_exponent <= max_exponent) && (m_exponent >= min_exponent)) Chris@102: { Chris@102: BOOST_ASSERT(eval_bit_test(m_data, bit_count - 1)); Chris@102: } Chris@102: else Chris@102: { Chris@102: BOOST_ASSERT(m_exponent > max_exponent); Chris@102: BOOST_ASSERT(m_exponent <= exponent_nan); Chris@102: BOOST_ASSERT(eval_is_zero(m_data)); Chris@102: } Chris@102: } Chris@102: template Chris@102: void serialize(Archive & ar, const unsigned int /*version*/) Chris@102: { Chris@102: ar & m_data; Chris@102: ar & m_exponent; Chris@102: ar & m_sign; Chris@102: } Chris@102: }; Chris@102: Chris@102: #ifdef BOOST_MSVC Chris@102: #pragma warning(pop) Chris@102: #endif Chris@102: Chris@102: template Chris@102: inline void copy_and_round(cpp_bin_float &res, Int &arg) Chris@102: { Chris@102: // Precondition: exponent of res must have been set before this function is called Chris@102: // as we may need to adjust it based on how many cpp_bin_float::bit_count in arg are set. Chris@102: using default_ops::eval_msb; Chris@102: using default_ops::eval_lsb; Chris@102: using default_ops::eval_left_shift; Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_right_shift; Chris@102: using default_ops::eval_increment; Chris@102: using default_ops::eval_get_sign; Chris@102: Chris@102: // cancellation may have resulted in arg being all zeros: Chris@102: if(eval_get_sign(arg) == 0) Chris@102: { Chris@102: res.exponent() = cpp_bin_float::exponent_zero; Chris@102: res.sign() = false; Chris@102: res.bits() = static_cast(0u); Chris@102: return; Chris@102: } Chris@102: int msb = eval_msb(arg); Chris@102: if(static_cast(cpp_bin_float::bit_count) > msb + 1) Chris@102: { Chris@102: // Must have had cancellation in subtraction, shift left and copy: Chris@102: res.bits() = arg; Chris@102: eval_left_shift(res.bits(), cpp_bin_float::bit_count - msb - 1); Chris@102: res.exponent() -= static_cast(cpp_bin_float::bit_count - msb - 1); Chris@102: } Chris@102: else if(static_cast(cpp_bin_float::bit_count) < msb + 1) Chris@102: { Chris@102: // We have more cpp_bin_float::bit_count than we need, so round as required, Chris@102: // first get the rounding bit: Chris@102: bool roundup = eval_bit_test(arg, msb - cpp_bin_float::bit_count); Chris@102: // Then check for a tie: Chris@102: if(roundup && (msb - cpp_bin_float::bit_count == eval_lsb(arg))) Chris@102: { Chris@102: // Ties round towards even: Chris@102: if(!eval_bit_test(arg, msb - cpp_bin_float::bit_count + 1)) Chris@102: roundup = false; Chris@102: } Chris@102: // Shift off the cpp_bin_float::bit_count we don't need: Chris@102: eval_right_shift(arg, msb - cpp_bin_float::bit_count + 1); Chris@102: res.exponent() += static_cast(msb - (int)cpp_bin_float::bit_count + 1); Chris@102: if(roundup) Chris@102: { Chris@102: eval_increment(arg); Chris@102: if(eval_bit_test(arg, cpp_bin_float::bit_count)) Chris@102: { Chris@102: // This happens very very rairly: Chris@102: eval_right_shift(arg, 1u); Chris@102: ++res.exponent(); Chris@102: } Chris@102: } Chris@102: res.bits() = arg; Chris@102: } Chris@102: else Chris@102: { Chris@102: res.bits() = arg; Chris@102: } Chris@102: BOOST_ASSERT((eval_msb(res.bits()) == cpp_bin_float::bit_count - 1)); Chris@102: Chris@102: if(res.exponent() > cpp_bin_float::max_exponent) Chris@102: { Chris@102: // Overflow: Chris@102: res.exponent() = cpp_bin_float::exponent_infinity; Chris@102: res.bits() = static_cast(0u); Chris@102: } Chris@102: else if(res.exponent() < cpp_bin_float::min_exponent) Chris@102: { Chris@102: // Underflow: Chris@102: res.exponent() = cpp_bin_float::exponent_zero; Chris@102: res.bits() = static_cast(0u); Chris@102: res.sign() = false; Chris@102: } Chris@102: } Chris@102: Chris@102: template Chris@102: inline void do_eval_add(cpp_bin_float &res, const cpp_bin_float &a, const cpp_bin_float &b) Chris@102: { Chris@102: using default_ops::eval_add; Chris@102: using default_ops::eval_bit_test; Chris@102: Chris@102: typename cpp_bin_float::double_rep_type dt; Chris@102: Chris@102: // Special cases first: Chris@102: switch(a.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: res = b; Chris@102: if(res.sign()) Chris@102: res.negate(); Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: if(b.exponent() == cpp_bin_float::exponent_nan) Chris@102: res = b; Chris@102: else Chris@102: res = a; Chris@102: return; // result is still infinite. Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = a; Chris@102: return; // result is still a NaN. Chris@102: } Chris@102: switch(b.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: res = a; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res = b; Chris@102: if(res.sign()) Chris@102: res.negate(); Chris@102: return; // result is infinite. Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = b; Chris@102: return; // result is a NaN. Chris@102: } Chris@102: Chris@102: typename cpp_bin_float::exponent_type e_diff = a.exponent() - b.exponent(); Chris@102: bool s = a.sign(); Chris@102: if(e_diff >= 0) Chris@102: { Chris@102: dt = a.bits(); Chris@102: if(e_diff < (int)cpp_bin_float::bit_count) Chris@102: { Chris@102: eval_left_shift(dt, e_diff); Chris@102: res.exponent() = a.exponent() - e_diff; Chris@102: eval_add(dt, b.bits()); Chris@102: } Chris@102: else Chris@102: res.exponent() = a.exponent(); Chris@102: } Chris@102: else Chris@102: { Chris@102: dt= b.bits(); Chris@102: if(-e_diff < (int)cpp_bin_float::bit_count) Chris@102: { Chris@102: eval_left_shift(dt, -e_diff); Chris@102: res.exponent() = b.exponent() + e_diff; Chris@102: eval_add(dt, a.bits()); Chris@102: } Chris@102: else Chris@102: res.exponent() = b.exponent(); Chris@102: } Chris@102: Chris@102: copy_and_round(res, dt); Chris@102: res.check_invariants(); Chris@102: if(res.sign() != s) Chris@102: res.negate(); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void do_eval_subtract(cpp_bin_float &res, const cpp_bin_float &a, const cpp_bin_float &b) Chris@102: { Chris@102: using default_ops::eval_subtract; Chris@102: using default_ops::eval_bit_test; Chris@102: Chris@102: typename cpp_bin_float::double_rep_type dt; Chris@102: Chris@102: // Special cases first: Chris@102: switch(a.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: if(b.exponent() == cpp_bin_float::exponent_nan) Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: else Chris@102: { Chris@102: res = b; Chris@102: if(!res.sign()) Chris@102: res.negate(); Chris@102: } Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: if((b.exponent() == cpp_bin_float::exponent_nan) || (b.exponent() == cpp_bin_float::exponent_infinity)) Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: else Chris@102: res = a; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = a; Chris@102: return; // result is still a NaN. Chris@102: } Chris@102: switch(b.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: res = a; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res.exponent() = cpp_bin_float::exponent_nan; Chris@102: res.sign() = false; Chris@102: res.bits() = static_cast(0u); Chris@102: return; // result is a NaN. Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = b; Chris@102: return; // result is still a NaN. Chris@102: } Chris@102: Chris@102: typename cpp_bin_float::exponent_type e_diff = a.exponent() - b.exponent(); Chris@102: bool s = a.sign(); Chris@102: if((e_diff > 0) || ((e_diff == 0) && a.bits().compare(b.bits()) >= 0)) Chris@102: { Chris@102: dt = a.bits(); Chris@102: if(e_diff < (int)cpp_bin_float::bit_count) Chris@102: { Chris@102: eval_left_shift(dt, e_diff); Chris@102: res.exponent() = a.exponent() - e_diff; Chris@102: eval_subtract(dt, b.bits()); Chris@102: } Chris@102: else Chris@102: res.exponent() = a.exponent(); Chris@102: } Chris@102: else Chris@102: { Chris@102: dt = b.bits(); Chris@102: if(-e_diff < (int)cpp_bin_float::bit_count) Chris@102: { Chris@102: eval_left_shift(dt, -e_diff); Chris@102: res.exponent() = b.exponent() + e_diff; Chris@102: eval_subtract(dt, a.bits()); Chris@102: } Chris@102: else Chris@102: res.exponent() = b.exponent(); Chris@102: s = !s; Chris@102: } Chris@102: Chris@102: copy_and_round(res, dt); Chris@102: if(res.sign() != s) Chris@102: res.negate(); Chris@102: res.check_invariants(); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_add(cpp_bin_float &res, const cpp_bin_float &a, const cpp_bin_float &b) Chris@102: { Chris@102: if(a.sign() == b.sign()) Chris@102: do_eval_add(res, a, b); Chris@102: else Chris@102: do_eval_subtract(res, a, b); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_add(cpp_bin_float &res, const cpp_bin_float &a) Chris@102: { Chris@102: return eval_add(res, res, a); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_subtract(cpp_bin_float &res, const cpp_bin_float &a, const cpp_bin_float &b) Chris@102: { Chris@102: if(a.sign() != b.sign()) Chris@102: do_eval_add(res, a, b); Chris@102: else Chris@102: do_eval_subtract(res, a, b); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_subtract(cpp_bin_float &res, const cpp_bin_float &a) Chris@102: { Chris@102: return eval_subtract(res, res, a); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_multiply(cpp_bin_float &res, const cpp_bin_float &a, const cpp_bin_float &b) Chris@102: { Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_multiply; Chris@102: Chris@102: // Special cases first: Chris@102: switch(a.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: if(b.exponent() == cpp_bin_float::exponent_nan) Chris@102: res = b; Chris@102: else Chris@102: res = a; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: switch(b.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: break; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = b; Chris@102: break; Chris@102: default: Chris@102: res = a; Chris@102: break; Chris@102: } Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = a; Chris@102: return; Chris@102: } Chris@102: if(b.exponent() > cpp_bin_float::max_exponent) Chris@102: { Chris@102: res = b; Chris@102: return; Chris@102: } Chris@102: if((a.exponent() > 0) && (b.exponent() > 0)) Chris@102: { Chris@102: if(cpp_bin_float::max_exponent + 2 - a.exponent() < b.exponent()) Chris@102: { Chris@102: // We will certainly overflow: Chris@102: res.exponent() = cpp_bin_float::exponent_infinity; Chris@102: res.sign() = a.sign() != b.sign(); Chris@102: res.bits() = static_cast(0u); Chris@102: return; Chris@102: } Chris@102: } Chris@102: if((a.exponent() < 0) && (b.exponent() < 0)) Chris@102: { Chris@102: if(cpp_bin_float::min_exponent - 2 - a.exponent() > b.exponent()) Chris@102: { Chris@102: // We will certainly underflow: Chris@102: res.exponent() = cpp_bin_float::exponent_zero; Chris@102: res.sign() = false; Chris@102: res.bits() = static_cast(0u); Chris@102: return; Chris@102: } Chris@102: } Chris@102: Chris@102: typename cpp_bin_float::double_rep_type dt; Chris@102: eval_multiply(dt, a.bits(), b.bits()); Chris@102: res.exponent() = a.exponent() + b.exponent() - cpp_bin_float::bit_count + 1; Chris@102: copy_and_round(res, dt); Chris@102: res.check_invariants(); Chris@102: res.sign() = a.sign() != b.sign(); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_multiply(cpp_bin_float &res, const cpp_bin_float &a) Chris@102: { Chris@102: eval_multiply(res, res, a); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_multiply(cpp_bin_float &res, const cpp_bin_float &a, const U &b) Chris@102: { Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_multiply; Chris@102: Chris@102: // Special cases first: Chris@102: switch(a.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: res = a; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: if(b == 0) Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: else Chris@102: res = a; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = a; Chris@102: return; Chris@102: } Chris@102: Chris@102: typename cpp_bin_float::double_rep_type dt; Chris@102: typedef typename boost::multiprecision::detail::canonical::double_rep_type>::type canon_ui_type; Chris@102: eval_multiply(dt, a.bits(), static_cast(b)); Chris@102: res.exponent() = a.exponent(); Chris@102: copy_and_round(res, dt); Chris@102: res.check_invariants(); Chris@102: res.sign() = a.sign(); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_multiply(cpp_bin_float &res, const U &b) Chris@102: { Chris@102: eval_multiply(res, res, b); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_multiply(cpp_bin_float &res, const cpp_bin_float &a, const S &b) Chris@102: { Chris@102: typedef typename make_unsigned::type ui_type; Chris@102: eval_multiply(res, a, static_cast(boost::multiprecision::detail::unsigned_abs(b))); Chris@102: if(b < 0) Chris@102: res.negate(); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_multiply(cpp_bin_float &res, const S &b) Chris@102: { Chris@102: eval_multiply(res, res, b); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_divide(cpp_bin_float &res, const cpp_bin_float &u, const cpp_bin_float &v) Chris@102: { Chris@102: using default_ops::eval_subtract; Chris@102: using default_ops::eval_qr; Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_get_sign; Chris@102: using default_ops::eval_increment; Chris@102: Chris@102: // Chris@102: // Special cases first: Chris@102: // Chris@102: switch(u.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: switch(v.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: res = u; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: switch(v.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: res = u; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: switch(v.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: { Chris@102: bool s = u.sign() != v.sign(); Chris@102: res = std::numeric_limits > >::infinity().backend(); Chris@102: res.sign() = s; Chris@102: return; Chris@102: } Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res.exponent() = cpp_bin_float::exponent_zero; Chris@102: res.bits() = limb_type(0); Chris@102: res.sign() = false; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: Chris@102: // We can scale u and v so that both are integers, then perform integer Chris@102: // division to obtain quotient q and remainder r, such that: Chris@102: // Chris@102: // q * v + r = u Chris@102: // Chris@102: // and hense: Chris@102: // Chris@102: // q + r/v = u/v Chris@102: // Chris@102: // From this, assuming q has cpp_bin_float::bit_count Chris@102: // bits we only need to determine whether Chris@102: // r/v is less than, equal to, or greater than 0.5 to determine rounding - Chris@102: // this we can do with a shift and comparison. Chris@102: // Chris@102: // We can set the exponent and sign of the result up front: Chris@102: // Chris@102: res.exponent() = u.exponent() - v.exponent() - 1; Chris@102: res.sign() = u.sign() != v.sign(); Chris@102: // Chris@102: // Now get the quotient and remainder: Chris@102: // Chris@102: typename cpp_bin_float::double_rep_type t(u.bits()), t2(v.bits()), q, r; Chris@102: eval_left_shift(t, cpp_bin_float::bit_count); Chris@102: eval_qr(t, t2, q, r); Chris@102: // Chris@102: // We now have either "cpp_bin_float::bit_count" Chris@102: // or "cpp_bin_float::bit_count+1" significant Chris@102: // bits in q. Chris@102: // Chris@102: static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; Chris@102: if(eval_bit_test(q, cpp_bin_float::bit_count)) Chris@102: { Chris@102: // Chris@102: // OK we have cpp_bin_float::bit_count+1 bits, Chris@102: // so we already have rounding info, Chris@102: // we just need to changes things if the last bit is 1 and either the Chris@102: // remainder is non-zero (ie we do not have a tie) or the quotient would Chris@102: // be odd if it were shifted to the correct number of bits (ie a tiebreak). Chris@102: // Chris@102: BOOST_ASSERT((eval_msb(q) == cpp_bin_float::bit_count)); Chris@102: if((q.limbs()[0] & 1u) && (eval_get_sign(r) || (q.limbs()[0] & 2u))) Chris@102: { Chris@102: eval_increment(q); Chris@102: } Chris@102: } Chris@102: else Chris@102: { Chris@102: // Chris@102: // We have exactly "cpp_bin_float::bit_count" bits in q. Chris@102: // Get rounding info, which we can get by comparing 2r with v. Chris@102: // We want to call copy_and_round to handle rounding and general cleanup, Chris@102: // so we'll left shift q and add some fake digits on the end to represent Chris@102: // how we'll be rounding. Chris@102: // Chris@102: BOOST_ASSERT((eval_msb(q) == cpp_bin_float::bit_count - 1)); Chris@102: static const unsigned lshift = cpp_bin_float::bit_count < limb_bits ? 2 : limb_bits; Chris@102: eval_left_shift(q, lshift); Chris@102: res.exponent() -= lshift; Chris@102: eval_left_shift(r, 1u); Chris@102: int c = r.compare(v.bits()); Chris@102: if(c == 0) Chris@102: q.limbs()[0] |= static_cast(1u) << (lshift - 1); Chris@102: else if(c > 0) Chris@102: q.limbs()[0] |= (static_cast(1u) << (lshift - 1)) + static_cast(1u); Chris@102: } Chris@102: copy_and_round(res, q); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_divide(cpp_bin_float &res, const cpp_bin_float &arg) Chris@102: { Chris@102: eval_divide(res, res, arg); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_divide(cpp_bin_float &res, const cpp_bin_float &u, const U &v) Chris@102: { Chris@102: using default_ops::eval_subtract; Chris@102: using default_ops::eval_qr; Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_get_sign; Chris@102: using default_ops::eval_increment; Chris@102: Chris@102: // Chris@102: // Special cases first: Chris@102: // Chris@102: switch(u.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: if(v == 0) Chris@102: { Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: res = u; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res = u; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: if(v == 0) Chris@102: { Chris@102: bool s = u.sign(); Chris@102: res = std::numeric_limits > >::infinity().backend(); Chris@102: res.sign() = s; Chris@102: return; Chris@102: } Chris@102: Chris@102: // We can scale u and v so that both are integers, then perform integer Chris@102: // division to obtain quotient q and remainder r, such that: Chris@102: // Chris@102: // q * v + r = u Chris@102: // Chris@102: // and hense: Chris@102: // Chris@102: // q + r/v = u/v Chris@102: // Chris@102: // From this, assuming q has "cpp_bin_float::bit_count" cpp_bin_float::bit_count, we only need to determine whether Chris@102: // r/v is less than, equal to, or greater than 0.5 to determine rounding - Chris@102: // this we can do with a shift and comparison. Chris@102: // Chris@102: // We can set the exponent and sign of the result up front: Chris@102: // Chris@102: int gb = msb(v); Chris@102: res.exponent() = u.exponent() - static_cast(gb) - static_cast(1); Chris@102: res.sign() = u.sign(); Chris@102: // Chris@102: // Now get the quotient and remainder: Chris@102: // Chris@102: typename cpp_bin_float::double_rep_type t(u.bits()), q, r; Chris@102: eval_left_shift(t, gb + 1); Chris@102: eval_qr(t, number::double_rep_type>::canonical_value(v), q, r); Chris@102: // Chris@102: // We now have either "cpp_bin_float::bit_count" or "cpp_bin_float::bit_count+1" significant cpp_bin_float::bit_count in q. Chris@102: // Chris@102: static const unsigned limb_bits = sizeof(limb_type) * CHAR_BIT; Chris@102: if(eval_bit_test(q, cpp_bin_float::bit_count)) Chris@102: { Chris@102: // Chris@102: // OK we have cpp_bin_float::bit_count+1 cpp_bin_float::bit_count, so we already have rounding info, Chris@102: // we just need to changes things if the last bit is 1 and the Chris@102: // remainder is non-zero (ie we do not have a tie). Chris@102: // Chris@102: BOOST_ASSERT((eval_msb(q) == cpp_bin_float::bit_count)); Chris@102: if((q.limbs()[0] & 1u) && eval_get_sign(r)) Chris@102: { Chris@102: eval_increment(q); Chris@102: } Chris@102: } Chris@102: else Chris@102: { Chris@102: // Chris@102: // We have exactly "cpp_bin_float::bit_count" cpp_bin_float::bit_count in q. Chris@102: // Get rounding info, which we can get by comparing 2r with v. Chris@102: // We want to call copy_and_round to handle rounding and general cleanup, Chris@102: // so we'll left shift q and add some fake cpp_bin_float::bit_count on the end to represent Chris@102: // how we'll be rounding. Chris@102: // Chris@102: BOOST_ASSERT((eval_msb(q) == cpp_bin_float::bit_count - 1)); Chris@102: static const unsigned lshift = cpp_bin_float::bit_count < limb_bits ? 2 : limb_bits; Chris@102: eval_left_shift(q, lshift); Chris@102: res.exponent() -= lshift; Chris@102: eval_left_shift(r, 1u); Chris@102: int c = r.compare(number::double_rep_type>::canonical_value(v)); Chris@102: if(c == 0) Chris@102: q.limbs()[0] |= static_cast(1u) << (lshift - 1); Chris@102: else if(c > 0) Chris@102: q.limbs()[0] |= (static_cast(1u) << (lshift - 1)) + static_cast(1u); Chris@102: } Chris@102: copy_and_round(res, q); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_divide(cpp_bin_float &res, const U &v) Chris@102: { Chris@102: eval_divide(res, res, v); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_divide(cpp_bin_float &res, const cpp_bin_float &u, const S &v) Chris@102: { Chris@102: typedef typename make_unsigned::type ui_type; Chris@102: eval_divide(res, u, static_cast(boost::multiprecision::detail::unsigned_abs(v))); Chris@102: if(v < 0) Chris@102: res.negate(); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_divide(cpp_bin_float &res, const S &v) Chris@102: { Chris@102: eval_divide(res, res, v); Chris@102: } Chris@102: Chris@102: template Chris@102: inline int eval_get_sign(const cpp_bin_float &arg) Chris@102: { Chris@102: return arg.exponent() == cpp_bin_float::exponent_zero ? 0 : arg.sign() ? -1 : 1; Chris@102: } Chris@102: Chris@102: template Chris@102: inline bool eval_is_zero(const cpp_bin_float &arg) Chris@102: { Chris@102: return arg.exponent() == cpp_bin_float::exponent_zero; Chris@102: } Chris@102: Chris@102: template Chris@102: inline bool eval_eq(const cpp_bin_float &a, cpp_bin_float &b) Chris@102: { Chris@102: return (a.exponent() == b.exponent()) Chris@102: && (a.sign() == b.sign()) Chris@102: && (a.bits().compare(b.bits()) == 0) Chris@102: && (a.exponent() != cpp_bin_float::exponent_nan); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_convert_to(long long *res, const cpp_bin_float &arg) Chris@102: { Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: *res = 0; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer.")); Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: *res = (std::numeric_limits::max)(); Chris@102: if(arg.sign()) Chris@102: *res = -*res; Chris@102: return; Chris@102: } Chris@102: typename cpp_bin_float::rep_type man(arg.bits()); Chris@102: typename mpl::if_c::exponent_type) < sizeof(int), int, typename cpp_bin_float::exponent_type>::type shift Chris@102: = (int)cpp_bin_float::bit_count - 1 - arg.exponent(); Chris@102: if(shift > (int)cpp_bin_float::bit_count - 1) Chris@102: { Chris@102: *res = 0; Chris@102: return; Chris@102: } Chris@102: if(arg.sign() && (arg.compare((std::numeric_limits::min)()) <= 0)) Chris@102: { Chris@102: *res = (std::numeric_limits::min)(); Chris@102: return; Chris@102: } Chris@102: else if(!arg.sign() && (arg.compare((std::numeric_limits::max)()) >= 0)) Chris@102: { Chris@102: *res = (std::numeric_limits::max)(); Chris@102: return; Chris@102: } Chris@102: eval_right_shift(man, shift); Chris@102: eval_convert_to(res, man); Chris@102: if(arg.sign()) Chris@102: { Chris@102: *res = -*res; Chris@102: } Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_convert_to(unsigned long long *res, const cpp_bin_float &arg) Chris@102: { Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: *res = 0; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Could not convert NaN to integer.")); Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: *res = (std::numeric_limits::max)(); Chris@102: return; Chris@102: } Chris@102: typename cpp_bin_float::rep_type man(arg.bits()); Chris@102: typename mpl::if_c::exponent_type) < sizeof(int), int, typename cpp_bin_float::exponent_type>::type shift Chris@102: = (int)cpp_bin_float::bit_count - 1 - arg.exponent(); Chris@102: if(shift > (int)cpp_bin_float::bit_count - 1) Chris@102: { Chris@102: *res = 0; Chris@102: return; Chris@102: } Chris@102: else if(shift < 0) Chris@102: { Chris@102: // TODO: what if we have fewer cpp_bin_float::bit_count than a long long? Chris@102: *res = (std::numeric_limits::max)(); Chris@102: return; Chris@102: } Chris@102: eval_right_shift(man, shift); Chris@102: eval_convert_to(res, man); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_convert_to(long double *res, const cpp_bin_float &arg) Chris@102: { Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: *res = 0; Chris@102: return; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: *res = std::numeric_limits::quiet_NaN(); Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: *res = (std::numeric_limits::infinity)(); Chris@102: if(arg.sign()) Chris@102: *res = -*res; Chris@102: return; Chris@102: } Chris@102: typename cpp_bin_float::exponent_type e = arg.exponent(); Chris@102: e -= cpp_bin_float::bit_count - 1; Chris@102: *res = std::ldexp(static_cast(*arg.bits().limbs()), e); Chris@102: for(unsigned i = 1; i < arg.bits().size(); ++i) Chris@102: { Chris@102: e += sizeof(*arg.bits().limbs()) * CHAR_BIT; Chris@102: *res += std::ldexp(static_cast(arg.bits().limbs()[i]), e); Chris@102: } Chris@102: if(arg.sign()) Chris@102: *res = -*res; Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_frexp(cpp_bin_float &res, const cpp_bin_float &arg, Exponent *e) Chris@102: { Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: *e = 0; Chris@102: res = arg; Chris@102: return; Chris@102: } Chris@102: res = arg; Chris@102: *e = arg.exponent() + 1; Chris@102: res.exponent() = -1; Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_frexp(cpp_bin_float &res, const cpp_bin_float &arg, I *pe) Chris@102: { Chris@102: Exponent e; Chris@102: eval_frexp(res, arg, &e); Chris@102: if((e > (std::numeric_limits::max)()) || (e < (std::numeric_limits::min)())) Chris@102: { Chris@102: BOOST_THROW_EXCEPTION(std::runtime_error("Exponent was outside of the range of the argument type to frexp.")); Chris@102: } Chris@102: *pe = static_cast(e); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_ldexp(cpp_bin_float &res, const cpp_bin_float &arg, Exponent e) Chris@102: { Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res = arg; Chris@102: return; Chris@102: } Chris@102: if((e > 0) && (cpp_bin_float::max_exponent - e < arg.exponent())) Chris@102: { Chris@102: // Overflow: Chris@102: res = std::numeric_limits > >::infinity().backend(); Chris@102: res.sign() = arg.sign(); Chris@102: } Chris@102: else if((e < 0) && (cpp_bin_float::min_exponent - e > arg.exponent())) Chris@102: { Chris@102: // Underflow: Chris@102: res = limb_type(0); Chris@102: } Chris@102: else Chris@102: { Chris@102: res = arg; Chris@102: res.exponent() += e; Chris@102: } Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_ldexp(cpp_bin_float &res, const cpp_bin_float &arg, I e) Chris@102: { Chris@102: typedef typename make_signed::type si_type; Chris@102: if(e > static_cast((std::numeric_limits::max)())) Chris@102: res = std::numeric_limits > >::infinity().backend(); Chris@102: else Chris@102: eval_ldexp(res, arg, static_cast(e)); Chris@102: } Chris@102: Chris@102: template Chris@102: inline typename enable_if_c::value>::type eval_ldexp(cpp_bin_float &res, const cpp_bin_float &arg, I e) Chris@102: { Chris@102: if((e > (std::numeric_limits::max)()) || (e < (std::numeric_limits::min)())) Chris@102: { Chris@102: res = std::numeric_limits > >::infinity().backend(); Chris@102: if(e < 0) Chris@102: res.negate(); Chris@102: } Chris@102: else Chris@102: eval_ldexp(res, arg, static_cast(e)); Chris@102: } Chris@102: Chris@102: /* Chris@102: * Sign manipulation Chris@102: */ Chris@102: Chris@102: template Chris@102: inline void eval_abs(cpp_bin_float &res, const cpp_bin_float &arg) Chris@102: { Chris@102: res = arg; Chris@102: res.sign() = false; Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_fabs(cpp_bin_float &res, const cpp_bin_float &arg) Chris@102: { Chris@102: res = arg; Chris@102: res.sign() = false; Chris@102: } Chris@102: Chris@102: template Chris@102: inline int eval_fpclassify(const cpp_bin_float &arg) Chris@102: { Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: return FP_ZERO; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: return FP_INFINITE; Chris@102: case cpp_bin_float::exponent_nan: Chris@102: return FP_NAN; Chris@102: } Chris@102: return FP_NORMAL; Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_sqrt(cpp_bin_float &res, const cpp_bin_float &arg) Chris@102: { Chris@102: using default_ops::eval_integer_sqrt; Chris@102: using default_ops::eval_bit_test; Chris@102: using default_ops::eval_increment; Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: res = arg; Chris@102: return; Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: if(arg.sign()) Chris@102: { Chris@102: res = std::numeric_limits > >::quiet_NaN().backend(); Chris@102: return; Chris@102: } Chris@102: Chris@102: typename cpp_bin_float::double_rep_type t(arg.bits()), r, s; Chris@102: eval_left_shift(t, arg.exponent() & 1 ? cpp_bin_float::bit_count : cpp_bin_float::bit_count - 1); Chris@102: eval_integer_sqrt(s, r, t); Chris@102: Chris@102: if(!eval_bit_test(s, cpp_bin_float::bit_count)) Chris@102: { Chris@102: // We have exactly the right number of cpp_bin_float::bit_count in the result, round as required: Chris@102: if(s.compare(r) < 0) Chris@102: { Chris@102: eval_increment(s); Chris@102: } Chris@102: } Chris@102: typename cpp_bin_float::exponent_type ae = arg.exponent(); Chris@102: res.exponent() = ae / 2; Chris@102: if((ae & 1) && (ae < 0)) Chris@102: --res.exponent(); Chris@102: copy_and_round(res, s); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_floor(cpp_bin_float &res, const cpp_bin_float &arg) Chris@102: { Chris@102: using default_ops::eval_increment; Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res = arg; Chris@102: return; Chris@102: } Chris@102: typename mpl::if_c::exponent_type) < sizeof(int), int, typename cpp_bin_float::exponent_type>::type shift = Chris@102: (int)cpp_bin_float::bit_count - arg.exponent() - 1; Chris@102: if((arg.exponent() > (int)cpp_bin_float::max_exponent) || (shift <= 0)) Chris@102: { Chris@102: // Either arg is already an integer, or a special value: Chris@102: res = arg; Chris@102: return; Chris@102: } Chris@102: if(shift >= (int)cpp_bin_float::bit_count) Chris@102: { Chris@102: res = static_cast(arg.sign() ? -1 : 0); Chris@102: return; Chris@102: } Chris@102: bool fractional = (int)eval_lsb(arg.bits()) < shift; Chris@102: res = arg; Chris@102: eval_right_shift(res.bits(), shift); Chris@102: if(fractional && res.sign()) Chris@102: { Chris@102: eval_increment(res.bits()); Chris@102: if(eval_msb(res.bits()) != cpp_bin_float::bit_count - 1 - shift) Chris@102: { Chris@102: // Must have extended result by one bit in the increment: Chris@102: --shift; Chris@102: ++res.exponent(); Chris@102: } Chris@102: } Chris@102: eval_left_shift(res.bits(), shift); Chris@102: } Chris@102: Chris@102: template Chris@102: inline void eval_ceil(cpp_bin_float &res, const cpp_bin_float &arg) Chris@102: { Chris@102: using default_ops::eval_increment; Chris@102: switch(arg.exponent()) Chris@102: { Chris@102: case cpp_bin_float::exponent_zero: Chris@102: case cpp_bin_float::exponent_nan: Chris@102: case cpp_bin_float::exponent_infinity: Chris@102: res = arg; Chris@102: return; Chris@102: } Chris@102: typename mpl::if_c::exponent_type) < sizeof(int), int, typename cpp_bin_float::exponent_type>::type shift = (int)cpp_bin_float::bit_count - arg.exponent() - 1; Chris@102: if((arg.exponent() > (int)cpp_bin_float::max_exponent) || (shift <= 0)) Chris@102: { Chris@102: // Either arg is already an integer, or a special value: Chris@102: res = arg; Chris@102: return; Chris@102: } Chris@102: if(shift >= (int)cpp_bin_float::bit_count) Chris@102: { Chris@102: res = static_cast(arg.sign() ? 0 : 1); Chris@102: return; Chris@102: } Chris@102: bool fractional = (int)eval_lsb(arg.bits()) < shift; Chris@102: res = arg; Chris@102: eval_right_shift(res.bits(), shift); Chris@102: if(fractional && !res.sign()) Chris@102: { Chris@102: eval_increment(res.bits()); Chris@102: if(eval_msb(res.bits()) != cpp_bin_float::bit_count - 1 - shift) Chris@102: { Chris@102: // Must have extended result by one bit in the increment: Chris@102: --shift; Chris@102: ++res.exponent(); Chris@102: } Chris@102: } Chris@102: eval_left_shift(res.bits(), shift); Chris@102: } Chris@102: Chris@102: } // namespace backends Chris@102: Chris@102: #ifdef BOOST_NO_SFINAE_EXPR Chris@102: Chris@102: namespace detail{ Chris@102: Chris@102: template Chris@102: struct is_explicitly_convertible, backends::cpp_bin_float > : public mpl::true_ {}; Chris@102: Chris@102: } Chris@102: #endif Chris@102: Chris@102: Chris@102: using backends::cpp_bin_float; Chris@102: using backends::digit_base_2; Chris@102: using backends::digit_base_10; Chris@102: Chris@102: template Chris@102: struct number_category > : public boost::mpl::int_{}; Chris@102: Chris@102: template Chris@102: struct expression_template_default > Chris@102: { Chris@102: static const expression_template_option value = is_void::value ? et_off : et_on; Chris@102: }; Chris@102: Chris@102: typedef number > cpp_bin_float_50; Chris@102: typedef number > cpp_bin_float_100; Chris@102: Chris@102: typedef number, et_off> cpp_bin_float_single; Chris@102: typedef number, et_off> cpp_bin_float_double; Chris@102: typedef number, et_off> cpp_bin_float_double_extended; Chris@102: typedef number, et_off> cpp_bin_float_quad; Chris@102: Chris@102: }} // namespaces Chris@102: Chris@102: #include Chris@102: #include Chris@102: Chris@102: namespace std{ Chris@102: Chris@102: // Chris@102: // numeric_limits [partial] specializations for the types declared in this header: Chris@102: // Chris@102: template Chris@102: class numeric_limits, ExpressionTemplates> > Chris@102: { Chris@102: typedef boost::multiprecision::number, ExpressionTemplates> number_type; Chris@102: public: Chris@102: BOOST_STATIC_CONSTEXPR bool is_specialized = true; Chris@102: static number_type (min)() Chris@102: { Chris@102: initializer.do_nothing(); Chris@102: static std::pair value; Chris@102: if(!value.first) Chris@102: { Chris@102: value.first = true; Chris@102: value.second = 1u; Chris@102: value.second.backend().exponent() = boost::multiprecision::cpp_bin_float::min_exponent; Chris@102: } Chris@102: return value.second; Chris@102: } Chris@102: static number_type (max)() Chris@102: { Chris@102: initializer.do_nothing(); Chris@102: static std::pair value; Chris@102: if(!value.first) Chris@102: { Chris@102: value.first = true; Chris@102: eval_complement(value.second.backend().bits(), value.second.backend().bits()); Chris@102: value.second.backend().exponent() = boost::multiprecision::cpp_bin_float::max_exponent; Chris@102: } Chris@102: return value.second; Chris@102: } Chris@102: BOOST_STATIC_CONSTEXPR number_type lowest() Chris@102: { Chris@102: return -(max)(); Chris@102: } Chris@102: BOOST_STATIC_CONSTEXPR int digits = boost::multiprecision::cpp_bin_float::bit_count; Chris@102: BOOST_STATIC_CONSTEXPR int digits10 = digits * 301 / 1000; Chris@102: // Is this really correct??? Chris@102: BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 2; Chris@102: BOOST_STATIC_CONSTEXPR bool is_signed = true; Chris@102: BOOST_STATIC_CONSTEXPR bool is_integer = false; Chris@102: BOOST_STATIC_CONSTEXPR bool is_exact = false; Chris@102: BOOST_STATIC_CONSTEXPR int radix = 2; Chris@102: static number_type epsilon() Chris@102: { Chris@102: initializer.do_nothing(); Chris@102: static std::pair value; Chris@102: if(!value.first) Chris@102: { Chris@102: value.first = true; Chris@102: value.second = 1; Chris@102: value.second = ldexp(value.second, 1 - (int)digits); Chris@102: } Chris@102: return value.second; Chris@102: } Chris@102: // What value should this be???? Chris@102: static number_type round_error() Chris@102: { Chris@102: // returns 0.5 Chris@102: initializer.do_nothing(); Chris@102: static std::pair value; Chris@102: if(!value.first) Chris@102: { Chris@102: value.first = true; Chris@102: value.second = 1; Chris@102: value.second = ldexp(value.second, -1); Chris@102: } Chris@102: return value.second; Chris@102: } Chris@102: BOOST_STATIC_CONSTEXPR typename boost::multiprecision::cpp_bin_float::exponent_type min_exponent = boost::multiprecision::cpp_bin_float::min_exponent; Chris@102: BOOST_STATIC_CONSTEXPR typename boost::multiprecision::cpp_bin_float::exponent_type min_exponent10 = (min_exponent / 1000) * 301L; Chris@102: BOOST_STATIC_CONSTEXPR typename boost::multiprecision::cpp_bin_float::exponent_type max_exponent = boost::multiprecision::cpp_bin_float::max_exponent; Chris@102: BOOST_STATIC_CONSTEXPR typename boost::multiprecision::cpp_bin_float::exponent_type max_exponent10 = (max_exponent / 1000) * 301L; Chris@102: BOOST_STATIC_CONSTEXPR bool has_infinity = true; Chris@102: BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = true; Chris@102: BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false; Chris@102: BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent; Chris@102: BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false; Chris@102: static number_type infinity() Chris@102: { Chris@102: // returns epsilon/2 Chris@102: initializer.do_nothing(); Chris@102: static std::pair value; Chris@102: if(!value.first) Chris@102: { Chris@102: value.first = true; Chris@102: value.second.backend().exponent() = boost::multiprecision::cpp_bin_float::exponent_infinity; Chris@102: } Chris@102: return value.second; Chris@102: } Chris@102: static number_type quiet_NaN() Chris@102: { Chris@102: return number_type(); Chris@102: } Chris@102: BOOST_STATIC_CONSTEXPR number_type signaling_NaN() Chris@102: { Chris@102: return number_type(0); Chris@102: } Chris@102: BOOST_STATIC_CONSTEXPR number_type denorm_min() { return number_type(0); } Chris@102: BOOST_STATIC_CONSTEXPR bool is_iec559 = false; Chris@102: BOOST_STATIC_CONSTEXPR bool is_bounded = true; Chris@102: BOOST_STATIC_CONSTEXPR bool is_modulo = false; Chris@102: BOOST_STATIC_CONSTEXPR bool traps = true; Chris@102: BOOST_STATIC_CONSTEXPR bool tinyness_before = false; Chris@102: BOOST_STATIC_CONSTEXPR float_round_style round_style = round_to_nearest; Chris@102: private: Chris@102: struct data_initializer Chris@102: { Chris@102: data_initializer() Chris@102: { Chris@102: std::numeric_limits > >::epsilon(); Chris@102: std::numeric_limits > >::round_error(); Chris@102: (std::numeric_limits > >::min)(); Chris@102: (std::numeric_limits > >::max)(); Chris@102: std::numeric_limits > >::infinity(); Chris@102: std::numeric_limits > >::quiet_NaN(); Chris@102: } Chris@102: void do_nothing()const{} Chris@102: }; Chris@102: static const data_initializer initializer; Chris@102: }; Chris@102: Chris@102: template Chris@102: const typename numeric_limits, ExpressionTemplates> >::data_initializer numeric_limits, ExpressionTemplates> >::initializer; Chris@102: Chris@102: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@102: Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST int numeric_limits, ExpressionTemplates> >::digits; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST int numeric_limits, ExpressionTemplates> >::digits10; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST int numeric_limits, ExpressionTemplates> >::max_digits10; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_signed; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_integer; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_exact; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST int numeric_limits, ExpressionTemplates> >::radix; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST typename boost::multiprecision::cpp_bin_float::exponent_type numeric_limits, ExpressionTemplates> >::min_exponent; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST typename boost::multiprecision::cpp_bin_float::exponent_type numeric_limits, ExpressionTemplates> >::min_exponent10; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST typename boost::multiprecision::cpp_bin_float::exponent_type numeric_limits, ExpressionTemplates> >::max_exponent; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST typename boost::multiprecision::cpp_bin_float::exponent_type numeric_limits, ExpressionTemplates> >::max_exponent10; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::has_infinity; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::has_quiet_NaN; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::has_signaling_NaN; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits, ExpressionTemplates> >::has_denorm; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::has_denorm_loss; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_iec559; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_bounded; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_modulo; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::traps; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::tinyness_before; Chris@102: template Chris@102: BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits, ExpressionTemplates> >::round_style; Chris@102: Chris@102: #endif Chris@102: Chris@102: } // namespace std Chris@102: Chris@102: #endif