| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 | /////////////////////////////////////////////////////////////////  Copyright 2011 John Maddock. Distributed under the Boost//  Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt#ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP#define BOOST_MATH_RATIONAL_ADAPTER_HPP#include <iostream>#include <iomanip>#include <sstream>#include <boost/cstdint.hpp>#include <boost/functional/hash_fwd.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)#endifnamespace 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);      return *this;   }#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; // saved for later      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   {      //      // We format the string ourselves so we can match what GMP's mpq type does:      //      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_&)   {      // Saving      integer_type n(m_value.numerator()), d(m_value.denominator());      ar&          boost::make_nvp("numerator", n);      ar&          boost::make_nvp("denominator", d);   }   template <class Archive>   void serialize(Archive& ar, const mpl::false_&)   {      // Loading      integer_type n, d;      ar&          boost::make_nvp("numerator", n);      ar&          boost::make_nvp("denominator", d);      m_value.assign(n, d);   }   template <class Archive>   void serialize(Archive& ar, const unsigned int /*version*/)   {      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){   //   // The generic conversion is as good as anything we can write here:   //   ::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){   using default_ops::eval_is_zero;   return eval_is_zero(val.data().numerator().backend());}template <class IntBackend>inline int eval_get_sign(const rational_adaptor<IntBackend>& val){   using default_ops::eval_get_sign;   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>inline std::size_t hash_value(const rational_adaptor<IntBackend>& val){   std::size_t result = hash_value(val.data().numerator());   boost::hash_combine(result, val.data().denominator());   return result;}} // namespace backendstemplate <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 Backend, expression_template_option ExpressionTemplates>struct component_type<number<backends::rational_adaptor<Backend>, ExpressionTemplates> >{   typedef number<Backend, ExpressionTemplates> 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_EXPRnamespace detail {template <class U, class IntBackend>struct is_explicitly_convertible<U, rational_adaptor<IntBackend> > : public is_explicitly_convertible<U, IntBackend>{};} // namespace detail#endif}} // namespace boost::multiprecisionnamespace 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_INITIALIZATIONtemplate <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} // namespace std#endif
 |