29 #ifndef PIRANHA_MP_RATIONAL_HPP    30 #define PIRANHA_MP_RATIONAL_HPP    33 #include <boost/functional/hash.hpp>    34 #include <boost/lexical_cast.hpp>    44 #include <type_traits>    45 #include <unordered_map>    48 #include <piranha/binomial.hpp>    49 #include <piranha/config.hpp>    50 #include <piranha/detail/demangle.hpp>    51 #include <piranha/detail/mp_rational_fwd.hpp>    53 #include <piranha/math.hpp>    54 #include <piranha/mp_integer.hpp>    55 #include <piranha/pow.hpp>    56 #include <piranha/print_tex_coefficient.hpp>    57 #include <piranha/s11n.hpp>    58 #include <piranha/safe_cast.hpp>    87 template <std::
size_t SSize>
    97     using is_interoperable_type = disjunction<mppp::mppp_impl::is_supported_interop<T>, std::is_same<T, int_type>>;
    99     template <
typename I0, 
typename I1>
   100     using nd_ctor_enabler
   101         = enable_if_t<conjunction<disjunction<std::is_integral<I0>, std::is_same<I0, int_type>>,
   102                                   disjunction<std::is_integral<I1>, std::is_same<I1, int_type>>>::value,
   105     template <
typename T>
   106     using generic_ctor_enabler = enable_if_t<is_interoperable_type<T>::value, 
int>;
   108     template <
typename T>
   109     using generic_in_place_enabler
   110         = enable_if_t<conjunction<is_interoperable_type<T>, negation<std::is_const<T>>>::value, 
int>;
   112     template <typename T, enable_if_t<std::is_integral<T>::value, 
int> = 0>
   113     void construct_from_interoperable(
const T &x)
   118     template <typename T, enable_if_t<std::is_same<T, int_type>::value, 
int> = 0>
   119     void construct_from_interoperable(
const T &x)
   124     template <typename Float, enable_if_t<std::is_floating_point<Float>::value, 
int> = 0>
   125     void construct_from_interoperable(
const Float &x)
   127         if (unlikely(!std::isfinite(x))) {
   128             piranha_throw(std::invalid_argument, 
"cannot construct a rational from a non-finite floating-point number");
   136         Float abs_x = std::abs(x);
   137         const unsigned radix = 
static_cast<unsigned>(std::numeric_limits<Float>::radix);
   139         int exp = std::ilogb(abs_x);
   142             const Float tmp = std::scalbn(Float(1), exp);
   143             if (unlikely(tmp == HUGE_VAL)) {
   144                 piranha_throw(std::invalid_argument, 
"output of std::scalbn is HUGE_VAL");
   148             if (abs_x == Float(0)) {
   156             exp = std::ilogb(abs_x);
   157             if (unlikely(exp == INT_MAX || exp == FP_ILOGBNAN)) {
   158                 piranha_throw(std::invalid_argument, 
"error calling std::ilogb");
   161         piranha_assert(abs_x < Float(1));
   163         while (abs_x != Float(0)) {
   164             abs_x = std::scalbln(abs_x, 1);
   165             if (unlikely(abs_x == HUGE_VAL)) {
   166                 piranha_throw(std::invalid_argument, 
"output of std::scalbn is HUGE_VAL");
   168             const auto t_abs_x = std::trunc(abs_x);
   176             m_num += 
static_cast<unsigned>(t_abs_x);
   186     template <
typename T>
   187     using cast_enabler = generic_ctor_enabler<T>;
   189     template <typename Float, enable_if_t<std::is_floating_point<Float>::value, 
int> = 0>
   190     Float convert_to_impl()
 const   196         return static_cast<Float
>(m_num) / static_cast<Float>(m_den);
   198     template <typename Integral, enable_if_t<std::is_integral<Integral>::value, 
int> = 0>
   199     Integral convert_to_impl()
 const   201         return static_cast<Integral
>(
static_cast<int_type>(*this));
   203     template <typename MpInteger, enable_if_t<std::is_same<MpInteger, int_type>::value, 
int> = 0>
   204     MpInteger convert_to_impl()
 const   206         return m_num / m_den;
   213         const bool u1 = m_den.
is_one(), u2 = other.m_den.is_one();
   217             m_num += other.m_num;
   222             m_num = m_num * other.m_den + other.m_num;
   227         } 
else if (m_den == other.m_den) {
   230             m_num += other.m_num;
   236             m_num *= other.m_den;
   238             m_den *= other.m_den;
   253     template <typename T, enable_if_t<std::is_integral<T>::value, 
int> = 0>
   258     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   261         return (*
this = static_cast<T>(*
this) + x);
   264     template <
typename T>
   273         return binary_plus_impl(q1, q2);
   275     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   278         return binary_plus_impl(q1, x);
   280     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   283         return binary_plus(q2, x);
   285     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   286     static T binary_plus(
const mp_rational &q1, 
const T &x)
   288         return x + 
static_cast<T
>(q1);
   290     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   291     static T binary_plus(
const T &x, 
const mp_rational &q2)
   293         return binary_plus(q2, x);
   301         const bool u1 = m_den.
is_one(), u2 = other.m_den.is_one();
   303             m_num -= other.m_num;
   305             m_num = m_num * other.m_den - other.m_num;
   308             m_num = m_num - m_den * other.m_num;
   309         } 
else if (m_den == other.m_den) {
   310             m_num -= other.m_num;
   313             m_num *= other.m_den;
   319             m_den *= other.m_den;
   335     template <typename T, enable_if_t<std::is_integral<T>::value, 
int> = 0>
   340     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   343         return (*
this = static_cast<T>(*
this) - x);
   346     template <
typename T>
   355         return binary_minus_impl(q1, q2);
   357     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   360         return binary_minus_impl(q1, x);
   362     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   365         auto retval = binary_minus(q2, x);
   369     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   370     static T binary_minus(
const mp_rational &q1, 
const T &x)
   372         return static_cast<T
>(q1) - x;
   374     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   375     static T binary_minus(
const T &x, 
const mp_rational &q2)
   377         return -binary_minus(q2, x);
   382         if (m_den.
is_one() && other.m_den.is_one()) {
   383             m_num *= other.m_num;
   386             m_num *= other.m_num;
   387             m_den *= other.m_den;
   400     template <typename T, enable_if_t<std::is_integral<T>::value, 
int> = 0>
   405     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   408         return (*
this = static_cast<T>(*
this) * x);
   411     template <
typename T>
   420         return binary_mult_impl(q1, q2);
   422     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   425         return binary_mult_impl(q1, x);
   427     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   430         return binary_mult(q2, x);
   432     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   433     static T binary_mult(
const mp_rational &q1, 
const T &x)
   435         return x * 
static_cast<T
>(q1);
   437     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   438     static T binary_mult(
const T &x, 
const mp_rational &q2)
   440         return binary_mult(q2, x);
   448         if (unlikely(
this == &other)) {
   452             m_num *= other.m_den;
   453             m_den *= other.m_num;
   464     template <typename T, enable_if_t<std::is_integral<T>::value, 
int> = 0>
   469     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   472         return (*
this = static_cast<T>(*
this) / x);
   475     template <
typename T>
   484         return binary_div_impl(q1, q2);
   486     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   489         return binary_div_impl(q1, x);
   491     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   498     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   499     static T binary_div(
const mp_rational &q1, 
const T &x)
   501         return static_cast<T
>(q1) / x;
   503     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   504     static T binary_div(
const T &x, 
const mp_rational &q2)
   506         return x / 
static_cast<T
>(q2);
   511         return q1.num() == q2.num() && q1.den() == q2.den();
   513     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   514     static bool binary_eq(
const mp_rational &q, 
const T &x)
   516         return q.den().is_one() && q.num() == x;
   518     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   519     static bool binary_eq(
const T &x, 
const mp_rational &q)
   521         return binary_eq(q, x);
   523     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   524     static bool binary_eq(
const mp_rational &q, 
const T &x)
   526         return static_cast<T
>(q) == x;
   528     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   529     static bool binary_eq(
const T &x, 
const mp_rational &q)
   531         return binary_eq(q, x);
   541         if (q1.m_den == q2.m_den) {
   542             return q1.m_num < q2.m_num;
   544         return q1.num() * q2.den() < q2.num() * q1.den();
   546     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   547     static bool binary_less_than(
const mp_rational &q, 
const T &x)
   549         return q.num() < q.den() * x;
   551     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   552     static bool binary_less_than(
const T &x, 
const mp_rational &q)
   554         return q.den() * x < q.num();
   556     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   557     static bool binary_less_than(
const mp_rational &q, 
const T &x)
   559         return static_cast<T
>(q) < x;
   561     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   562     static bool binary_less_than(
const T &x, 
const mp_rational &q)
   564         return x < static_cast<T>(q);
   569         if (q1.m_den == q2.m_den) {
   570             return q1.m_num > q2.m_num;
   572         return q1.num() * q2.den() > q2.num() * q1.den();
   574     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   575     static bool binary_greater_than(
const mp_rational &q, 
const T &x)
   577         return q.num() > q.den() * x;
   579     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
   580     static bool binary_greater_than(
const T &x, 
const mp_rational &q)
   582         return q.den() * x > q.num();
   584     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   585     static bool binary_greater_than(
const mp_rational &q, 
const T &x)
   587         return static_cast<T
>(q) > x;
   589     template <typename T, enable_if_t<std::is_floating_point<T>::value, 
int> = 0>
   590     static bool binary_greater_than(
const T &x, 
const mp_rational &q)
   592         return x > 
static_cast<T
>(q);
   597         using mpq_struct_t = std::remove_extent<::mpq_t>::type;
   600         explicit mpq_view(
const mp_rational &q) : m_n_view(q.
num().get_mpz_view()), m_d_view(q.
den().get_mpz_view())
   603             auto n_ptr = m_n_view.get();
   604             auto d_ptr = m_d_view.get();
   605             mpq_numref(&m_mpq)->_mp_alloc = n_ptr->_mp_alloc;
   606             mpq_numref(&m_mpq)->_mp_size = n_ptr->_mp_size;
   607             mpq_numref(&m_mpq)->_mp_d = n_ptr->_mp_d;
   608             mpq_denref(&m_mpq)->_mp_alloc = d_ptr->_mp_alloc;
   609             mpq_denref(&m_mpq)->_mp_size = d_ptr->_mp_size;
   610             mpq_denref(&m_mpq)->_mp_d = d_ptr->_mp_d;
   612         mpq_view(
const mpq_view &) = 
delete;
   613         mpq_view(mpq_view &&) = 
default;
   614         mpq_view &
operator=(
const mpq_view &) = 
delete;
   615         mpq_view &
operator=(mpq_view &&) = 
delete;
   616         operator mpq_struct_t 
const *() 
const   620         mpq_struct_t 
const *
get() 
const   626         decltype(std::declval<const int_type &>().get_mpz_view()) m_n_view;
   627         decltype(
std::declval<const 
int_type &>().get_mpz_view()) m_d_view;
   631     template <typename T>
   632     using pow_enabler = enable_if_t<
   636     friend class 
boost::serialization::access;
   637     template <class Archive>
   638     void save(Archive &ar, 
unsigned)
 const   643     template <class Archive, enable_if_t<!std::is_same<Archive, boost::archive::binary_iarchive>::value, 
int> = 0>
   644     void load(Archive &ar, 
unsigned)
   654     template <class Archive, enable_if_t<std::is_same<Archive, boost::archive::binary_iarchive>::value, 
int> = 0>
   655     void load(Archive &ar, 
unsigned)
   660         m_num = std::move(
num);
   661         m_den = std::move(
den);
   663     BOOST_SERIALIZATION_SPLIT_MEMBER()
   698     template <
typename I0, 
typename I1, nd_ctor_enabler<I0, I1> = 0>
   699     explicit mp_rational(
const I0 &n, 
const I1 &d) : m_num(n), m_den(d)
   701         if (unlikely(m_den.sgn() == 0)) {
   716     template <
typename T, 
generic_ctor_enabler<T> = 0>
   719         construct_from_interoperable(x);
   738         std::size_t num_size = 0u;
   739         while (*ptr != 
'\0' && *ptr != 
'/') {
   743         m_num = 
int_type(std::string(str, str + num_size));
   745             m_den = 
int_type(std::string(ptr + 1u));
   766         piranha_assert(m_den.sgn() > 0);
   783         if (unlikely(
this == &other)) {
   786         m_num = std::move(other.m_num);
   787         m_den = std::move(other.m_den);
   806     template <
typename T, 
generic_ctor_enabler<T> = 0>
   839         return (*
this = str.c_str());
   856         if (q.m_den.is_one()) {
   859             os << q.m_num << 
'/' << q.m_den;
   877         std::getline(is, tmp_str);
   915         return mpq_view{*
this};
   933         const auto gcd = 
math::gcd(m_num, m_den);
   934         return (m_num.sgn() != 0 && (gcd == 1 || gcd == -1)) || (m_num.sgn() == 0 && m_den == 1);
   953         divexact(m_num, m_num, gcd);
   954         divexact(m_den, m_den, gcd);
   956         if (m_den.sgn() == -1) {
   976     template <
typename T, cast_enabler<T> = 0>
   977     explicit operator T()
 const   997     explicit mp_rational(const ::mpq_t q) : m_num(mpq_numref(q)), m_den(mpq_denref(q))
   999         if (unlikely(m_den.sgn() == 0)) {
  1029         if (unlikely(
den.
sgn() <= 0)) {
  1030             piranha_throw(std::invalid_argument, 
"cannot set non-positive denominator in rational");
  1085     template <
typename T>
  1088         return in_place_add(x);
  1105     template <
typename T, 
generic_in_place_enabler<T> = 0>
  1108         return x = 
static_cast<T
>(q + x);
  1134     template <
typename T, 
typename U>
  1135     friend auto operator+(
const T &x, 
const U &y) -> decltype(mp_rational::binary_plus(x, y))
  1137         return mp_rational::binary_plus(x, y);
  1196     template <
typename T>
  1199         return in_place_sub(x);
  1216     template <
typename T, 
generic_in_place_enabler<T> = 0>
  1219         return x = 
static_cast<T
>(x - q);
  1245     template <
typename T, 
typename U>
  1246     friend auto operator-(
const T &x, 
const U &y) -> decltype(mp_rational::binary_minus(x, y))
  1248         return mp_rational::binary_minus(x, y);
  1270     template <
typename T>
  1273         return in_place_mult(x);
  1290     template <
typename T, 
generic_in_place_enabler<T> = 0>
  1293         return x = 
static_cast<T
>(x * q);
  1319     template <
typename T, 
typename U>
  1320     friend auto operator*(
const T &x, 
const U &y) -> decltype(mp_rational::binary_mult(x, y))
  1322         return mp_rational::binary_mult(x, y);
  1345     template <
typename T>
  1351         return in_place_div(x);
  1368     template <
typename T, 
generic_in_place_enabler<T> = 0>
  1371         return x = 
static_cast<T
>(x / q);
  1398     template <
typename T, 
typename U>
  1399     friend auto operator/(
const T &x, 
const U &y) -> decltype(mp_rational::binary_div(x, y))
  1401         return mp_rational::binary_div(x, y);
  1426     template <
typename T, 
typename U>
  1427     friend auto operator==(
const T &x, 
const U &y) -> decltype(mp_rational::binary_eq(x, y))
  1429         return mp_rational::binary_eq(x, y);
  1452     template <
typename T, 
typename U>
  1453     friend auto operator!=(
const T &x, 
const U &y) -> decltype(!mp_rational::binary_eq(x, y))
  1455         return !mp_rational::binary_eq(x, y);
  1480     template <
typename T, 
typename U>
  1481     friend auto operator<(
const T &x, 
const U &y) -> decltype(mp_rational::binary_less_than(x, y))
  1483         return mp_rational::binary_less_than(x, y);
  1506     template <
typename T, 
typename U>
  1507     friend auto operator>=(
const T &x, 
const U &y) -> decltype(!mp_rational::binary_less_than(x, y))
  1509         return !mp_rational::binary_less_than(x, y);
  1534     template <
typename T, 
typename U>
  1535     friend auto operator>(
const T &x, 
const U &y) -> decltype(mp_rational::binary_greater_than(x, y))
  1537         return mp_rational::binary_greater_than(x, y);
  1560     template <
typename T, 
typename U>
  1561     friend auto operator<=(
const T &x, 
const U &y) -> decltype(!mp_rational::binary_greater_than(x, y))
  1563         return !mp_rational::binary_greater_than(x, y);
  1582     template <
typename T, pow_enabler<T> = 0>
  1602             if (retval.m_den.sgn() < 0) {
  1616         if (retval.m_num.sgn() < 0) {
  1629         std::size_t retval = std::hash<int_type>()(m_num);
  1630         boost::hash_combine(retval, std::hash<int_type>()(m_den));
  1636     template <typename T, enable_if_t<std::is_unsigned<T>::value, 
int> = 0>
  1637     static bool generic_binomial_check_k(
const T &, 
const T &)
  1641     template <typename T, enable_if_t<!std::is_unsigned<T>::value, 
int> = 0>
  1642     static bool generic_binomial_check_k(
const T &k, 
const T &zero)
  1648     template <
typename T, 
typename U>
  1649     static T generic_binomial(
const T &x, 
const U &k)
  1651         const U zero(0), one(1);
  1652         if (generic_binomial_check_k(k, zero)) {
  1653             piranha_throw(std::invalid_argument, 
"negative k value in binomial coefficient");
  1659         T tmp(x), retval = x / T(k);
  1661         for (
auto i = static_cast<U>(k - one); i >= one; --i, --tmp) {
  1683     template <
typename T, enable_if_t<disjunction<std::is_
integral<T>, std::is_same<T, 
int_type>>::value, 
int> = 0>
  1686         if (m_den.is_one()) {
  1697         return generic_binomial(*
this, n);
  1700 #if defined(PIRANHA_WITH_MSGPACK)  1702     template <
typename Stream>
  1703     using msgpack_pack_enabler
  1705     template <
typename U>
  1706     using msgpack_convert_enabler = enable_if_t<has_msgpack_convert<typename U::int_type>::value, 
int>;
  1724     template <
typename Stream, msgpack_pack_enabler<Stream> = 0>
  1749     template <
typename U = mp_rational, msgpack_convert_enabler<U> = 0>
  1752         std::array<msgpack::object, 2u> v;
  1758             m_num = std::move(
num);
  1759             m_den = std::move(
den);
  1774 inline namespace literals
  1792 inline namespace impl
  1797 struct is_mp_rational : std::false_type {
  1800 template <std::
size_t SSize>
  1801 struct is_mp_rational<
mp_rational<SSize>> : std::true_type {
  1805 template <
typename, 
typename>
  1806 struct is_same_mp_rational : std::false_type {
  1809 template <std::
size_t SSize>
  1817 template <
typename T, 
typename Rational>
  1818 struct is_mp_rational_interoperable_type : mppp::mppp_impl::is_supported_interop<T> {
  1821 template <
typename T, std::
size_t SSize>
  1822 struct is_mp_rational_interoperable_type<T, 
mp_rational<SSize>>
  1823     : disjunction<mppp::mppp_impl::is_supported_interop<T>, std::is_same<T, typename mp_rational<SSize>::int_type>> {
  1828 template <std::
size_t SSize>
  1843         if (cf.den().is_one()) {
  1847         auto num = cf.num();
  1852         os << 
"\\frac{" << 
num << 
"}{" << cf.den() << 
"}";
  1860 template <std::
size_t SSize>
  1875 template <std::
size_t SSize>
  1890 template <std::
size_t SSize>
  1903 inline namespace impl
  1907 template <
typename T, 
typename U>
  1908 using math_rational_pow_enabler
  1909     = enable_if_t<disjunction<conjunction<is_mp_rational<T>, is_mp_rational_interoperable_type<U, T>>,
  1910                               conjunction<is_mp_rational<U>, is_mp_rational_interoperable_type<T, U>>,
  1911                               is_same_mp_rational<T, U>>::value>;
  1933 template <
typename T, 
typename U>
  1934 struct pow_impl<T, U, math_rational_pow_enabler<T, U>> {
  1936     template <std::
size_t SSize, 
typename T2>
  1941     template <std::size_t SSize, typename T2, enable_if_t<std::is_floating_point<T2>::value, 
int> = 0>
  1944         return math::pow(static_cast<T2>(b), e);
  1946     template <std::size_t SSize, typename T2, enable_if_t<std::is_floating_point<T2>::value, 
int> = 0>
  1949         return math::pow(e, static_cast<T2>(b));
  1951     template <std::
size_t SSize>
  1959             const auto sign = e.num().sgn();
  1971         if (!e.den().is_one()) {
  1973                           "unable to raise rational to a rational power whose denominator is not 1");
  1975         return b.pow(e.num());
  1977     template <std::size_t SSize, 
typename T2,
  1978               enable_if_t<disjunction<std::is_integral<T2>, is_mp_integer<T2>>::value, 
int> = 0>
  1981         using ret_t = decltype(
math::pow(b, e.num()));
  1986             const auto sign = e.num().sgn();
  1995         if (!e.den().is_one()) {
  1997                           "unable to raise an integral to a rational power whose denominator is not 1");
  2001     using ret_type = decltype(impl(std::declval<const T &>(), std::declval<const U &>()));
  2024 template <std::
size_t SSize>
  2039         piranha_throw(std::invalid_argument, 
"cannot compute the sine of a non-zero rational");
  2044 template <std::
size_t SSize>
  2059         piranha_throw(std::invalid_argument, 
"cannot compute the cosine of a non-zero rational");
  2064 template <std::
size_t SSize>
  2079 template <std::
size_t SSize>
  2092 inline namespace impl
  2096 template <
typename T, 
typename U>
  2097 using math_rational_binomial_enabler = math_rational_pow_enabler<T, U>;
  2118 template <
typename T, 
typename U>
  2121     template <std::
size_t SSize, 
typename T2>
  2122     static auto impl(
const mp_rational<SSize> &x, 
const T2 &y) -> decltype(x.binomial(y))
  2124         return x.binomial(y);
  2126     template <std::size_t SSize, typename T2, enable_if_t<std::is_floating_point<T2>::value, 
int> = 0>
  2131     template <std::size_t SSize, typename T2, enable_if_t<std::is_floating_point<T2>::value, 
int> = 0>
  2136     template <std::
size_t SSize>
  2139         return math::binomial(static_cast<double>(x), static_cast<double>(y));
  2141     template <std::size_t SSize, 
typename T2,
  2142               enable_if_t<disjunction<std::is_integral<T2>, is_mp_integer<T2>>::value, 
int> = 0>
  2145         return math::binomial(static_cast<double>(x), static_cast<double>(y));
  2147     using ret_type = decltype(impl(std::declval<const T &>(), std::declval<const U &>()));
  2168 inline namespace impl
  2171 template <
typename To, 
typename From>
  2172 using sc_rat_enabler = enable_if_t<
  2173     disjunction<conjunction<is_mp_rational<To>, disjunction<std::is_arithmetic<From>, is_mp_integer<From>>>,
  2174                 conjunction<is_mp_rational<From>, disjunction<std::is_integral<To>, is_mp_integer<To>>>>::value>;
  2184 template <
typename To, 
typename From>
  2187     template <
typename T, enable_if_t<disjunction<std::is_arithmetic<T>, is_mp_
integer<T>>::value, 
int> = 0>
  2188     static To impl(
const T &x)
  2193         } 
catch (
const std::invalid_argument &) {
  2195                                                  + 
" of type '" + detail::demangle<T>()
  2196                                                  + 
"' to a rational, as the conversion would not preserve the value");
  2199     template <typename T, enable_if_t<is_mp_rational<T>::value, 
int> = 0>
  2200     static To impl(
const T &q)
  2202         if (unlikely(!q.den().is_one())) {
  2204                                                  + 
" to the integral type '" + detail::demangle<To>()
  2205                                                  + 
"', as the rational value as non-unitary denominator");
  2208             return static_cast<To
>(q);
  2209         } 
catch (
const std::overflow_error &) {
  2211                                                  + 
" to the integral type '" + detail::demangle<To>()
  2212                                                  + 
"', as the conversion cannot preserve the value");
  2233 inline namespace impl
  2236 template <
typename Archive, std::
size_t SSize>
  2237 using mp_rational_boost_save_enabler
  2238     = enable_if_t<has_boost_save<Archive, typename mp_rational<SSize>::int_type>::value>;
  2240 template <
typename Archive, std::
size_t SSize>
  2241 using mp_rational_boost_load_enabler
  2242     = enable_if_t<has_boost_load<Archive, typename mp_rational<SSize>::int_type>::value>;
  2255 template <
typename Archive, std::
size_t SSize>
  2272 template <
typename Archive, std::
size_t SSize>
  2277 #if defined(PIRANHA_WITH_MSGPACK)  2279 inline namespace impl
  2282 template <
typename Stream, 
typename T>
  2283 using mp_rational_msgpack_pack_enabler
  2284     = enable_if_t<conjunction<is_mp_rational<T>, is_detected<msgpack_pack_member_t, Stream, T>>::value>;
  2286 template <
typename T>
  2287 using mp_rational_msgpack_convert_enabler
  2288     = enable_if_t<conjunction<is_mp_rational<T>, is_detected<msgpack_convert_member_t, T>>::value>;
  2297 template <
typename Stream, 
typename T>
  2311         q.msgpack_pack(p, f);
  2321 template <
typename T>
  2335         q.msgpack_convert(o, f);
  2346 template <std::
size_t SSize>
 math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation. 
auto gcd(const T &a, const U &b) -> decltype(gcd_impl< T, U >()(a, b))
GCD. 
void operator()(msgpack::packer< Stream > &p, const T &q, msgpack_format f) const
Call operator. 
friend auto operator<=(const T &x, const U &y) -> decltype(!mp_rational::binary_greater_than(x, y))
Generic less-than or equal operator involving piranha::mp_rational. 
void boost_load(Archive &ar, T &x)
Load from Boost archive. 
Default functor for the implementation of piranha::math::negate(). 
auto operator+=(const T &x) -> decltype(this->in_place_add(x))
In-place addition. 
Multiprecision integer class. 
void canonicalise()
Canonicalise. 
mp_integer< SSize > int_type
The underlying piranha::mp_integer type used to represent numerator and denominator. 
Default implementation of piranha::boost_load(). 
friend T & operator-=(T &x, const mp_rational &q)
Generic in-place subtraction with piranha::mp_rational. 
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object. 
size_t result_type
Result type. 
bool is_canonical() const
Canonicality check. 
friend auto operator>(const T &x, const U &y) -> decltype(mp_rational::binary_greater_than(x, y))
Generic greater-than operator involving piranha::mp_rational. 
mp_rational< SSize > operator()(const mp_rational< SSize > &q) const
Call operator. 
mp_rational< SSize > operator()(const mp_rational< SSize > &q) const
Call operator. 
Default functor for the implementation of piranha::math::binomial(). 
friend auto operator+(const T &x, const U &y) -> decltype(mp_rational::binary_plus(x, y))
Generic binary addition involving piranha::mp_rational. 
void msgpack_pack(msgpack::packer< Stream > &p, msgpack_format f) const
Pack in msgpack format. 
Default functor for the implementation of piranha::math::is_zero(). 
Implementation of piranha::boost_load() via the Boost API. 
bool operator()(const mp_rational< SSize > &q) const
Call operator. 
friend T & operator+=(T &x, const mp_rational &q)
Generic in-place addition with piranha::mp_rational. 
auto operator*=(const T &x) -> decltype(this->in_place_mult(x))
In-place multiplication. 
mp_rational(const ::mpq_t q)
Constructor from mpq_t. 
friend auto operator<(const T &x, const U &y) -> decltype(mp_rational::binary_less_than(x, y))
Generic less-than operator involving piranha::mp_rational. 
mp_rational< 1 > rational
Alias for piranha::mp_rational with 1 static limb. 
mp_rational operator++(int)
Post-increment operator. 
Default functor for the implementation of piranha::math::sin(). 
Default implementation of piranha::boost_save(). 
friend std::ostream & operator<<(std::ostream &os, const mp_rational &q)
Stream operator. 
void negate(T &x)
In-place negation. 
friend auto operator>=(const T &x, const U &y) -> decltype(!mp_rational::binary_less_than(x, y))
Generic greater-than or equal operator involving piranha::mp_rational. 
Default functor for the implementation of piranha::math::cos(). 
void msgpack_convert(const msgpack::object &o, msgpack_format f)
Convert from msgpack object. 
ret_type operator()(const T &x, const U &y) const
Call operator. 
mp_rational(const std::string &str)
Constructor from C++ string. 
std::size_t hash() const
Hash value. 
result_type operator()(const argument_type &q) const
Hash operator. 
Default functor for the implementation of piranha::math::pow(). 
mp_rational & operator=(const mp_rational &other)=default
Copy assignment operator. 
void operator()(mp_rational< SSize > &q) const
Call operator. 
mp_rational operator-() const
Negated copy. 
mp_rational & operator=(const T &x)
Generic assignment operator. 
ret_type operator()(const T &b, const U &e) const
Call operator. 
mp_rational(mp_rational &&other) noexcept
Move constructor. 
friend auto operator/(const T &x, const U &y) -> decltype(mp_rational::binary_div(x, y))
Generic binary division involving piranha::mp_rational. 
void operator()(T &q, const msgpack::object &o, msgpack_format f) const
Call operator. 
mp_rational binomial(const T &n) const
Binomial coefficient. 
friend auto operator==(const T &x, const U &y) -> decltype(mp_rational::binary_eq(x, y))
Generic equality operator involving piranha::mp_rational. 
Default functor for the implementation of piranha::msgpack_convert(). 
#define piranha_throw(exception_type,...)
Exception-throwing macro. 
Default functor for the implementation of piranha::msgpack_pack(). 
int_type & _den()
Mutable reference to the denominator. 
Exception for signalling division by zero. 
msgpack_format
Serialization format for msgpack. 
friend T & operator*=(T &x, const mp_rational &q)
Generic in-place multiplication with piranha::mp_rational. 
mp_integer & neg()
Negate in-place. 
mp_rational pow(const T &exp) const
Exponentiation. 
mp_rational & operator=(const char *str)
Assignment operator from C string. 
Default functor for the implementation of piranha::math::partial(). 
Multiple precision rational class. 
~mp_rational()
Destructor. 
Default implementation of piranha::safe_cast(). 
mp_rational(const char *str)
Constructor from C string. 
mp_rational()
Default constructor. 
mp_rational operator+() const
Identity operator. 
friend std::istream & operator>>(std::istream &is, mp_rational &q)
Overload input stream operator for piranha::mp_rational. 
Default functor for the implementation of piranha::convert_to(). 
bool is_zero(const T &x)
Zero test. 
mp_rational< SSize > operator()(const mp_rational< SSize > &, const std::string &) const
Call operator. 
void operator()(std::ostream &os, const mp_rational< SSize > &cf) const
Call operator. 
mp_rational & operator=(const std::string &str)
Assignment operator from C++ string. 
Implementation of piranha::boost_save() via the Boost API. 
mp_rational(const I0 &n, const I1 &d)
Constructor from numerator/denominator pair. 
math_binomial_type< T, U > binomial(const T &x, const U &y)
Generalised binomial coefficient. 
mp_rational abs() const
Absolute value. 
const int_type & den() const
Get const reference to the denominator. 
mp_rational & operator++()
Pre-increment operator. 
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream. 
bool is_one() const
Test if the value is equal to one. 
Detect the presence of piranha::msgpack_pack(). 
void _set_den(const int_type &den)
Set denominator. 
friend auto operator-(const T &x, const U &y) -> decltype(mp_rational::binary_minus(x, y))
Generic binary subtraction involving piranha::mp_rational. 
bool operator()(const mp_rational< SSize > &q) const
Call operator. 
void multiply_accumulate(T &x, const T &y, const T &z)
Multiply-accumulate. 
auto operator-=(const T &x) -> decltype(this->in_place_sub(x))
In-place subtraction. 
friend auto operator*(const T &x, const U &y) -> decltype(mp_rational::binary_mult(x, y))
Generic binary multiplication involving piranha::mp_rational. 
To operator()(const From &x) const
Call operator. 
int_type & _num()
Mutable reference to the numerator. 
mp_rational< SSize > operator()(const mp_rational< SSize > &q) const
Call operator. 
piranha::mp_rational< SSize > argument_type
Argument type. 
mp_rational operator--(int)
Post-decrement operator. 
mp_rational(const T &x)
Generic constructor. 
void boost_save(Archive &ar, const T &x)
Save to Boost archive. 
void negate()
Negate in-place. 
Default functor for piranha::print_tex_coefficient(). 
mpq_view get_mpq_view() const
Get an mpq view of this. 
Default functor for the implementation of piranha::math::abs(). 
friend T & operator/=(T &x, const mp_rational &q)
Generic in-place division with piranha::mp_rational. 
auto operator/=(const T &x) -> decltype(this->in_place_div(x))
In-place division. 
mp_rational & operator=(mp_rational &&other) noexcept
Move assignment operator. 
const int_type & num() const
Get const reference to the numerator. 
Exception to signal failure in piranha::safe_cast(). 
Default functor for the implementation of piranha::math::is_unitary(). 
bool is_unitary(const T &x)
Unitary test. 
mp_rational & operator--()
Pre-decrement operator. 
friend auto operator!=(const T &x, const U &y) -> decltype(!mp_rational::binary_eq(x, y))
Generic inequality operator involving piranha::mp_rational.