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.