123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- #ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP
- #define BOOST_MATH_RATIONAL_ADAPTER_HPP
- #include <iostream>
- #include <iomanip>
- #include <sstream>
- #include <boost/cstdint.hpp>
- #include <boost/multiprecision/number.hpp>
- #ifdef BOOST_MSVC
- # pragma warning(push)
- # pragma warning(disable:4512 4127)
- #endif
- #include <boost/rational.hpp>
- #ifdef BOOST_MSVC
- # pragma warning(pop)
- #endif
- namespace boost{
- namespace multiprecision{
- namespace backends{
- template <class IntBackend>
- struct rational_adaptor
- {
- typedef number<IntBackend> integer_type;
- typedef boost::rational<integer_type> rational_type;
- typedef typename IntBackend::signed_types signed_types;
- typedef typename IntBackend::unsigned_types unsigned_types;
- typedef typename IntBackend::float_types float_types;
- rational_adaptor() BOOST_MP_NOEXCEPT_IF(noexcept(rational_type())) {}
- rational_adaptor(const rational_adaptor& o) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<const rational_type&>()))
- {
- m_value = o.m_value;
- }
- rational_adaptor(const IntBackend& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<const IntBackend&>()))) : m_value(o) {}
- template <class U>
- rational_adaptor(const U& u, typename enable_if_c<is_convertible<U, IntBackend>::value>::type* = 0)
- : m_value(static_cast<integer_type>(u)){}
- template <class U>
- explicit rational_adaptor(const U& u,
- typename enable_if_c<
- boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_convertible<U, IntBackend>::value
- >::type* = 0)
- : m_value(IntBackend(u)){}
- template <class U>
- typename enable_if_c<(boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_arithmetic<U>::value), rational_adaptor&>::type operator = (const U& u)
- {
- m_value = IntBackend(u);
- }
- #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
- rational_adaptor(rational_adaptor&& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<rational_type>()))) : m_value(static_cast<rational_type&&>(o.m_value)) {}
- rational_adaptor(IntBackend&& o) BOOST_MP_NOEXCEPT_IF(noexcept(rational_type(std::declval<IntBackend>()))) : m_value(static_cast<IntBackend&&>(o)) {}
- rational_adaptor& operator = (rational_adaptor&& o) BOOST_MP_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<rational_type>()))
- {
- m_value = static_cast<rational_type&&>(o.m_value);
- return *this;
- }
- #endif
- rational_adaptor& operator = (const rational_adaptor& o)
- {
- m_value = o.m_value;
- return *this;
- }
- rational_adaptor& operator = (const IntBackend& o)
- {
- m_value = o;
- return *this;
- }
- template <class Int>
- typename enable_if<is_integral<Int>, rational_adaptor&>::type operator = (Int i)
- {
- m_value = i;
- return *this;
- }
- template <class Float>
- typename enable_if<is_floating_point<Float>, rational_adaptor&>::type operator = (Float i)
- {
- int e;
- Float f = std::frexp(i, &e);
- f = std::ldexp(f, std::numeric_limits<Float>::digits);
- e -= std::numeric_limits<Float>::digits;
- integer_type num(f);
- integer_type denom(1u);
- if(e > 0)
- {
- num <<= e;
- }
- else if(e < 0)
- {
- denom <<= -e;
- }
- m_value.assign(num, denom);
- return *this;
- }
- rational_adaptor& operator = (const char* s)
- {
- std::string s1;
- multiprecision::number<IntBackend> v1, v2;
- char c;
- bool have_hex = false;
- const char* p = s;
- 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'))))
- {
- if(c == 'x' || c == 'X')
- have_hex = true;
- s1.append(1, c);
- ++s;
- }
- v1.assign(s1);
- s1.erase();
- if(c == '/')
- {
- ++s;
- 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'))))
- {
- if(c == 'x' || c == 'X')
- have_hex = true;
- s1.append(1, c);
- ++s;
- }
- v2.assign(s1);
- }
- else
- v2 = 1;
- if(*s)
- {
- BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Could not parse the string \"") + p + std::string("\" as a valid rational number.")));
- }
- data().assign(v1, v2);
- return *this;
- }
- void swap(rational_adaptor& o)
- {
- std::swap(m_value, o.m_value);
- }
- std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
- {
-
-
-
- std::string result = data().numerator().str(digits, f);
- if(data().denominator() != 1)
- {
- result.append(1, '/');
- result.append(data().denominator().str(digits, f));
- }
- return result;
- }
- void negate()
- {
- m_value = -m_value;
- }
- int compare(const rational_adaptor& o)const
- {
- return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
- }
- template <class Arithmatic>
- typename enable_if_c<is_arithmetic<Arithmatic>::value && !is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
- {
- return m_value > i ? 1 : (m_value < i ? -1 : 0);
- }
- template <class Arithmatic>
- typename enable_if_c<is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
- {
- rational_adaptor r;
- r = i;
- return this->compare(r);
- }
- rational_type& data() { return m_value; }
- const rational_type& data()const { return m_value; }
- template <class Archive>
- void serialize(Archive& ar, const mpl::true_&)
- {
-
- integer_type n(m_value.numerator()), d(m_value.denominator());
- ar & n;
- ar & d;
- }
- template <class Archive>
- void serialize(Archive& ar, const mpl::false_&)
- {
-
- integer_type n, d;
- ar & n;
- ar & d;
- m_value.assign(n, d);
- }
- template <class Archive>
- void serialize(Archive& ar, const unsigned int )
- {
- typedef typename Archive::is_saving tag;
- serialize(ar, tag());
- }
- private:
- rational_type m_value;
- };
- template <class IntBackend>
- inline void eval_add(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
- {
- result.data() += o.data();
- }
- template <class IntBackend>
- inline void eval_subtract(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
- {
- result.data() -= o.data();
- }
- template <class IntBackend>
- inline void eval_multiply(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
- {
- result.data() *= o.data();
- }
- template <class IntBackend>
- inline void eval_divide(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
- {
- using default_ops::eval_is_zero;
- if(eval_is_zero(o))
- {
- BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero."));
- }
- result.data() /= o.data();
- }
- template <class R, class IntBackend>
- inline typename enable_if_c<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
- {
-
-
-
- ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend);
- }
- template <class R, class IntBackend>
- inline typename enable_if_c<(number_category<R>::value != number_kind_integer) && (number_category<R>::value != number_kind_floating_point)>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
- {
- typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
- comp_t num(backend.data().numerator());
- comp_t denom(backend.data().denominator());
- *result = num.template convert_to<R>();
- *result /= denom.template convert_to<R>();
- }
- template <class R, class IntBackend>
- inline typename enable_if_c<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
- {
- typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
- comp_t t = backend.data().numerator();
- t /= backend.data().denominator();
- *result = t.template convert_to<R>();
- }
- template <class IntBackend>
- inline bool eval_is_zero(const rational_adaptor<IntBackend>& val)
- {
- return eval_is_zero(val.data().numerator().backend());
- }
- template <class IntBackend>
- inline int eval_get_sign(const rational_adaptor<IntBackend>& val)
- {
- return eval_get_sign(val.data().numerator().backend());
- }
- template<class IntBackend, class V>
- inline void assign_components(rational_adaptor<IntBackend>& result, const V& v1, const V& v2)
- {
- result.data().assign(v1, v2);
- }
- }
- template<class IntBackend>
- struct expression_template_default<backends::rational_adaptor<IntBackend> > : public expression_template_default<IntBackend> {};
-
- template<class IntBackend>
- struct number_category<backends::rational_adaptor<IntBackend> > : public mpl::int_<number_kind_rational>{};
- using boost::multiprecision::backends::rational_adaptor;
- template <class T>
- struct component_type<rational_adaptor<T> >
- {
- typedef number<T> type;
- };
- template <class IntBackend, expression_template_option ET>
- inline number<IntBackend, ET> numerator(const number<rational_adaptor<IntBackend>, ET>& val)
- {
- return val.backend().data().numerator();
- }
- template <class IntBackend, expression_template_option ET>
- inline number<IntBackend, ET> denominator(const number<rational_adaptor<IntBackend>, ET>& val)
- {
- return val.backend().data().denominator();
- }
- #ifdef BOOST_NO_SFINAE_EXPR
- namespace detail{
- template<class U, class IntBackend>
- struct is_explicitly_convertible<U, rational_adaptor<IntBackend> > : public is_explicitly_convertible<U, IntBackend> {};
- }
- #endif
- }}
- namespace std{
- template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
- class numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> > : public std::numeric_limits<boost::multiprecision::number<IntBackend, ExpressionTemplates> >
- {
- typedef std::numeric_limits<boost::multiprecision::number<IntBackend> > base_type;
- typedef boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend> > number_type;
- public:
- BOOST_STATIC_CONSTEXPR bool is_integer = false;
- BOOST_STATIC_CONSTEXPR bool is_exact = true;
- BOOST_STATIC_CONSTEXPR number_type (min)() { return (base_type::min)(); }
- BOOST_STATIC_CONSTEXPR number_type (max)() { return (base_type::max)(); }
- BOOST_STATIC_CONSTEXPR number_type lowest() { return -(max)(); }
- BOOST_STATIC_CONSTEXPR number_type epsilon() { return base_type::epsilon(); }
- BOOST_STATIC_CONSTEXPR number_type round_error() { return epsilon() / 2; }
- BOOST_STATIC_CONSTEXPR number_type infinity() { return base_type::infinity(); }
- BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return base_type::quiet_NaN(); }
- BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return base_type::signaling_NaN(); }
- BOOST_STATIC_CONSTEXPR number_type denorm_min() { return base_type::denorm_min(); }
- };
- #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
- template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
- BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_integer;
- template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
- BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_exact;
- #endif
- }
- #endif
|