Chris@16: /////////////////////////////////////////////////////////////// Chris@16: // Copyright 2011 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ Chris@16: Chris@16: #ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP Chris@16: #define BOOST_MATH_RATIONAL_ADAPTER_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable:4512 4127) Chris@16: #endif Chris@16: #include Chris@16: #ifdef BOOST_MSVC Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: namespace boost{ Chris@16: namespace multiprecision{ Chris@16: namespace backends{ Chris@16: Chris@16: template Chris@16: struct rational_adaptor Chris@16: { Chris@16: typedef number integer_type; Chris@16: typedef boost::rational rational_type; Chris@16: Chris@16: typedef typename IntBackend::signed_types signed_types; Chris@16: typedef typename IntBackend::unsigned_types unsigned_types; Chris@16: typedef typename IntBackend::float_types float_types; Chris@16: Chris@101: rational_adaptor() BOOST_NOEXCEPT_IF(noexcept(rational_type())) {} Chris@101: rational_adaptor(const rational_adaptor& o) BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval())) Chris@16: { Chris@16: m_value = o.m_value; Chris@16: } Chris@101: rational_adaptor(const IntBackend& o) BOOST_NOEXCEPT_IF(noexcept(rational_type(std::declval()))) : m_value(o) {} Chris@16: Chris@16: template Chris@16: rational_adaptor(const U& u, typename enable_if_c::value>::type* = 0) Chris@101: : m_value(static_cast(u)){} Chris@16: template Chris@16: explicit rational_adaptor(const U& u, Chris@16: typename enable_if_c< Chris@16: boost::multiprecision::detail::is_explicitly_convertible::value && !is_convertible::value Chris@16: >::type* = 0) Chris@16: : m_value(IntBackend(u)){} Chris@16: template Chris@16: typename enable_if_c<(boost::multiprecision::detail::is_explicitly_convertible::value && !is_arithmetic::value), rational_adaptor&>::type operator = (const U& u) Chris@16: { Chris@16: m_value = IntBackend(u); Chris@16: } Chris@16: Chris@16: #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES Chris@101: rational_adaptor(rational_adaptor&& o) BOOST_NOEXCEPT_IF(noexcept(rational_type(std::declval()))) : m_value(static_cast(o.m_value)) {} Chris@101: rational_adaptor(IntBackend&& o) BOOST_NOEXCEPT_IF(noexcept(rational_type(std::declval()))) : m_value(static_cast(o)) {} Chris@101: rational_adaptor& operator = (rational_adaptor&& o) BOOST_NOEXCEPT_IF(noexcept(std::declval() = std::declval())) Chris@16: { Chris@16: m_value = static_cast(o.m_value); Chris@16: return *this; Chris@16: } Chris@16: #endif Chris@16: rational_adaptor& operator = (const rational_adaptor& o) Chris@16: { Chris@16: m_value = o.m_value; Chris@16: return *this; Chris@16: } Chris@16: rational_adaptor& operator = (const IntBackend& o) Chris@16: { Chris@16: m_value = o; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: typename enable_if, rational_adaptor&>::type operator = (Int i) Chris@16: { Chris@16: m_value = i; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: typename enable_if, rational_adaptor&>::type operator = (Float i) Chris@16: { Chris@16: int e; Chris@16: Float f = std::frexp(i, &e); Chris@16: f = std::ldexp(f, std::numeric_limits::digits); Chris@16: e -= std::numeric_limits::digits; Chris@16: integer_type num(f); Chris@16: integer_type denom(1u); Chris@16: if(e > 0) Chris@16: { Chris@16: num <<= e; Chris@16: } Chris@16: else if(e < 0) Chris@16: { Chris@16: denom <<= -e; Chris@16: } Chris@16: m_value.assign(num, denom); Chris@16: return *this; Chris@16: } Chris@16: rational_adaptor& operator = (const char* s) Chris@16: { Chris@16: std::string s1; Chris@16: multiprecision::number v1, v2; Chris@16: char c; Chris@16: bool have_hex = false; Chris@16: const char* p = s; // saved for later Chris@16: Chris@16: while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) Chris@16: { Chris@16: if(c == 'x' || c == 'X') Chris@16: have_hex = true; Chris@16: s1.append(1, c); Chris@16: ++s; Chris@16: } Chris@16: v1.assign(s1); Chris@16: s1.erase(); Chris@16: if(c == '/') Chris@16: { Chris@16: ++s; Chris@16: while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F')))) Chris@16: { Chris@16: if(c == 'x' || c == 'X') Chris@16: have_hex = true; Chris@16: s1.append(1, c); Chris@16: ++s; Chris@16: } Chris@16: v2.assign(s1); Chris@16: } Chris@16: else Chris@16: v2 = 1; Chris@16: if(*s) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Could parse the string \"") + p + std::string("\" as a valid rational number."))); Chris@16: } Chris@16: data().assign(v1, v2); Chris@16: return *this; Chris@16: } Chris@16: void swap(rational_adaptor& o) Chris@16: { Chris@16: std::swap(m_value, o.m_value); Chris@16: } Chris@16: std::string str(std::streamsize digits, std::ios_base::fmtflags f)const Chris@16: { Chris@16: // Chris@16: // We format the string ourselves so we can match what GMP's mpq type does: Chris@16: // Chris@16: std::string result = data().numerator().str(digits, f); Chris@16: if(data().denominator() != 1) Chris@16: { Chris@16: result.append(1, '/'); Chris@16: result.append(data().denominator().str(digits, f)); Chris@16: } Chris@16: return result; Chris@16: } Chris@16: void negate() Chris@16: { Chris@16: m_value = -m_value; Chris@16: } Chris@16: int compare(const rational_adaptor& o)const Chris@16: { Chris@16: return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0); Chris@16: } Chris@16: template Chris@101: typename enable_if_c::value && !is_floating_point::value, int>::type compare(Arithmatic i)const Chris@16: { Chris@16: return m_value > i ? 1 : (m_value < i ? -1 : 0); Chris@16: } Chris@101: template Chris@101: typename enable_if_c::value, int>::type compare(Arithmatic i)const Chris@101: { Chris@101: rational_adaptor r; Chris@101: r = i; Chris@101: return this->compare(r); Chris@101: } Chris@16: rational_type& data() { return m_value; } Chris@16: const rational_type& data()const { return m_value; } Chris@16: Chris@16: template Chris@16: void serialize(Archive& ar, const mpl::true_&) Chris@16: { Chris@16: // Saving Chris@16: integer_type n(m_value.numerator()), d(m_value.denominator()); Chris@16: ar & n; Chris@16: ar & d; Chris@16: } Chris@16: template Chris@16: void serialize(Archive& ar, const mpl::false_&) Chris@16: { Chris@16: // Loading Chris@16: integer_type n, d; Chris@16: ar & n; Chris@16: ar & d; Chris@16: m_value.assign(n, d); Chris@16: } Chris@16: template Chris@16: void serialize(Archive& ar, const unsigned int /*version*/) Chris@16: { Chris@16: typedef typename Archive::is_saving tag; Chris@16: serialize(ar, tag()); Chris@16: } Chris@16: private: Chris@16: rational_type m_value; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void eval_add(rational_adaptor& result, const rational_adaptor& o) Chris@16: { Chris@16: result.data() += o.data(); Chris@16: } Chris@16: template Chris@16: inline void eval_subtract(rational_adaptor& result, const rational_adaptor& o) Chris@16: { Chris@16: result.data() -= o.data(); Chris@16: } Chris@16: template Chris@16: inline void eval_multiply(rational_adaptor& result, const rational_adaptor& o) Chris@16: { Chris@16: result.data() *= o.data(); Chris@16: } Chris@16: template Chris@16: inline void eval_divide(rational_adaptor& result, const rational_adaptor& o) Chris@16: { Chris@16: using default_ops::eval_is_zero; Chris@16: if(eval_is_zero(o)) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero.")); Chris@16: } Chris@16: result.data() /= o.data(); Chris@16: } Chris@16: Chris@16: template Chris@101: inline typename enable_if_c::value == number_kind_floating_point>::type eval_convert_to(R* result, const rational_adaptor& backend) Chris@16: { Chris@101: // Chris@101: // The generic conversion is as good as anything we can write here: Chris@101: // Chris@101: ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend); Chris@101: } Chris@101: Chris@101: template Chris@101: inline typename enable_if_c<(number_category::value != number_kind_integer) && (number_category::value != number_kind_floating_point)>::type eval_convert_to(R* result, const rational_adaptor& backend) Chris@101: { Chris@101: typedef typename component_type > >::type comp_t; Chris@101: comp_t num(backend.data().numerator()); Chris@101: comp_t denom(backend.data().denominator()); Chris@101: *result = num.template convert_to(); Chris@101: *result /= denom.template convert_to(); Chris@101: } Chris@101: Chris@101: template Chris@101: inline typename enable_if_c::value == number_kind_integer>::type eval_convert_to(R* result, const rational_adaptor& backend) Chris@101: { Chris@101: typedef typename component_type > >::type comp_t; Chris@101: comp_t t = backend.data().numerator(); Chris@101: t /= backend.data().denominator(); Chris@101: *result = t.template convert_to(); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool eval_is_zero(const rational_adaptor& val) Chris@16: { Chris@16: return eval_is_zero(val.data().numerator().backend()); Chris@16: } Chris@16: template Chris@16: inline int eval_get_sign(const rational_adaptor& val) Chris@16: { Chris@16: return eval_get_sign(val.data().numerator().backend()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void assign_components(rational_adaptor& result, const V& v1, const V& v2) Chris@16: { Chris@16: result.data().assign(v1, v2); Chris@16: } Chris@16: Chris@16: } // namespace backends Chris@16: Chris@16: template Chris@16: struct expression_template_default > : public expression_template_default {}; Chris@16: Chris@16: template Chris@16: struct number_category > : public mpl::int_{}; Chris@16: Chris@16: using boost::multiprecision::backends::rational_adaptor; Chris@16: Chris@16: template Chris@16: struct component_type > Chris@16: { Chris@16: typedef number type; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline number numerator(const number, ET>& val) Chris@16: { Chris@16: return val.backend().data().numerator(); Chris@16: } Chris@16: template Chris@16: inline number denominator(const number, ET>& val) Chris@16: { Chris@16: return val.backend().data().denominator(); Chris@16: } Chris@16: Chris@16: #ifdef BOOST_NO_SFINAE_EXPR Chris@16: Chris@16: namespace detail{ Chris@16: Chris@16: template Chris@16: struct is_explicitly_convertible > : public is_explicitly_convertible {}; Chris@16: Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: }} // namespaces Chris@16: Chris@16: Chris@16: namespace std{ Chris@16: Chris@16: template Chris@16: class numeric_limits, ExpressionTemplates> > : public std::numeric_limits > Chris@16: { Chris@16: typedef std::numeric_limits > base_type; Chris@16: typedef boost::multiprecision::number > number_type; Chris@16: public: Chris@16: BOOST_STATIC_CONSTEXPR bool is_integer = false; Chris@16: BOOST_STATIC_CONSTEXPR bool is_exact = true; Chris@16: BOOST_STATIC_CONSTEXPR number_type (min)() { return (base_type::min)(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type (max)() { return (base_type::max)(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type lowest() { return -(max)(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type epsilon() { return base_type::epsilon(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type round_error() { return epsilon() / 2; } Chris@16: BOOST_STATIC_CONSTEXPR number_type infinity() { return base_type::infinity(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return base_type::quiet_NaN(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return base_type::signaling_NaN(); } Chris@16: BOOST_STATIC_CONSTEXPR number_type denorm_min() { return base_type::denorm_min(); } Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@16: Chris@16: template Chris@16: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_integer; Chris@16: template Chris@16: BOOST_CONSTEXPR_OR_CONST bool numeric_limits, ExpressionTemplates> >::is_exact; Chris@16: Chris@16: #endif Chris@16: Chris@16: Chris@16: } Chris@16: Chris@16: #endif