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