29 #ifndef PIRANHA_MP_INTEGER_HPP 30 #define PIRANHA_MP_INTEGER_HPP 38 #include <type_traits> 42 #include <piranha/config.hpp> 43 #include <piranha/detail/demangle.hpp> 45 #include <piranha/is_key.hpp> 46 #include <piranha/math.hpp> 47 #define MPPP_WITH_LONG_DOUBLE 48 #include <piranha/mppp/mp++.hpp> 49 #undef MPPP_WITH_LONG_DOUBLE 50 #include <piranha/s11n.hpp> 51 #include <piranha/safe_cast.hpp> 52 #include <piranha/symbol_utils.hpp> 59 template <std::
size_t SSize>
71 struct is_mp_integer : std::false_type {
74 template <std::
size_t SSize>
75 struct is_mp_integer<
mp_integer<SSize>> : std::true_type {
79 template <
typename,
typename>
80 struct is_same_mp_integer : std::false_type {
83 template <std::
size_t SSize>
92 template <std::
size_t SSize>
109 template <std::
size_t SSize>
124 template <std::
size_t SSize>
141 template <std::
size_t SSize>
158 inline namespace impl
162 template <std::
size_t SSize>
163 inline mp_integer<SSize> mp_integer_abs_wrapper(
const mp_integer<SSize> &n)
172 template <std::
size_t SSize>
184 return mp_integer_abs_wrapper(n);
189 template <std::
size_t SSize>
204 piranha_throw(std::invalid_argument,
"cannot compute the sine of a non-zero integer");
209 template <std::
size_t SSize>
224 piranha_throw(std::invalid_argument,
"cannot compute the cosine of a non-zero integer");
229 template <std::
size_t SSize>
253 template <std::
size_t SSize>
256 if (unlikely(sgn(n) < 0)) {
257 piranha_throw(std::domain_error,
"cannot compute the factorial of the negative integer " + n.
to_string());
260 fac_ui(retval, static_cast<unsigned long>(n));
269 template <
typename T,
typename U,
typename =
void>
274 inline namespace impl
278 template <
typename T,
typename U>
279 using math_ipow_subs_t_
281 std::declval<const integer &>(), std::declval<const U &>()));
283 template <
typename T,
typename U>
284 using math_ipow_subs_t = enable_if_t<is_returnable<math_ipow_subs_t_<T, U>>::value, math_ipow_subs_t_<T, U>>;
311 template <
typename T,
typename U>
312 inline math_ipow_subs_t<T, U>
ipow_subs(
const T &x,
const std::string &name,
const integer &n,
const U &y)
318 template <std::
size_t SSize>
335 template <std::
size_t SSize>
352 template <std::
size_t SSize>
369 template <std::
size_t SSize>
384 tdiv_qr(out, r, a, b);
389 inline namespace impl
393 template <
typename T,
typename U>
394 using math_mp_integer_gcd_enabler
395 = enable_if_t<disjunction<conjunction<std::is_integral<T>, is_mp_integer<U>, std::is_constructible<U, const T &>>,
396 conjunction<std::is_integral<U>, is_mp_integer<T>, std::is_constructible<T, const U &>>,
397 is_same_mp_integer<T, U>>::value>;
400 template <std::
size_t SSize>
401 inline mp_integer<SSize> mp_integer_gcd_wrapper(
const mp_integer<SSize> &a,
const mp_integer<SSize> &b)
422 template <
typename T,
typename U>
423 struct gcd_impl<T, U, math_mp_integer_gcd_enabler<T, U>> {
431 template <std::
size_t SSize>
434 return mp_integer_gcd_wrapper(a, b);
443 template <std::
size_t SSize,
typename T1>
455 template <std::
size_t SSize,
typename T1>
458 return operator()(b, a);
463 template <std::
size_t SSize>
481 inline namespace impl
486 template <
typename T,
typename U,
typename Int>
487 using math_ipow_subs_int_t_
488 = decltype(
math::ipow_subs(std::declval<const T &>(), std::declval<const std::string &>(),
489 integer{std::declval<const Int &>()}, std::declval<const U &>()));
491 template <
typename T,
typename U,
typename Int>
492 using math_ipow_subs_int_t = enable_if_t<std::is_integral<Int>::value, math_ipow_subs_int_t_<T, U, Int>>;
517 template <
typename T,
typename U,
typename Int>
518 inline math_ipow_subs_int_t<T, U, Int>
ipow_subs(
const T &x,
const std::string &name,
const Int &n,
const U &y)
529 template <
typename T,
typename U>
532 template <
typename T1,
typename U1>
533 using ipow_subs_t = decltype(
math::ipow_subs(std::declval<const T1 &>(), std::declval<std::string const &>(),
534 std::declval<integer const &>(), std::declval<const U1 &>()));
535 static const bool implementation_defined = is_detected<ipow_subs_t, T, U>::value;
539 static const bool value = implementation_defined;
542 template <
typename T,
typename U>
556 template <
typename Key,
typename T>
559 PIRANHA_TT_CHECK(
is_key, uncvref_t<Key>);
560 template <
typename Key1,
typename T1>
561 using key_ipow_subs_t = decltype(
562 std::declval<const Key1 &>().ipow_subs(std::declval<const symbol_idx &>(), std::declval<const integer &>(),
563 std::declval<const T1 &>(), std::declval<const symbol_fset &>()));
564 template <
typename T1>
565 struct check_result_type : std::false_type {
567 template <
typename Res>
568 struct check_result_type<
std::vector<std::pair<Res, uncvref_t<Key>>>> : std::true_type {
570 static const bool implementation_defined = check_result_type<detected_t<key_ipow_subs_t, Key, T>>
::value;
574 static const bool value = implementation_defined;
578 template <
typename Key,
typename T>
581 inline namespace literals
599 inline namespace impl
603 using mpz_size_t = mppp::mppp_impl::mpz_size_t;
605 inline mpz_size_t mp_integer_safe_abs_size(mpz_size_t s)
607 if (unlikely(s < -detail::safe_abs_sint<mpz_size_t>::value)) {
608 piranha_throw(std::overflow_error,
"the number of limbs is too large");
610 return static_cast<mpz_size_t
>(s >= 0 ? s : -s);
617 namespace serialization
620 template <
typename Archive, std::size_t SSize,
621 piranha::enable_if_t<std::is_same<Archive, boost::archive::binary_oarchive>::value,
int> = 0>
628 const auto size = int_u.g_st()._mp_size;
630 std::for_each(int_u.g_st().m_limbs.data(), int_u.g_st().m_limbs.data() + (size >= 0 ? size : -size),
636 std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + ::mpz_size(&int_u.g_dy()),
641 template <
typename Archive, std::size_t SSize,
642 piranha::enable_if_t<std::is_same<Archive, boost::archive::binary_iarchive>::value,
int> = 0>
653 const bool pstatus = n.
promote();
665 piranha_assert(int_u.is_static());
668 auto size = int_u.g_st()._mp_size;
669 if (unlikely(size > int_u.g_st().s_size || size < -int_u.g_st().s_size)) {
670 piranha_throw(std::invalid_argument,
"cannot deserialize a static integer with signed limb size " 671 + std::to_string(size) +
" (the maximum static limb size is " 672 + std::to_string(int_u.g_st().s_size) +
")");
675 size = (size >= 0) ? size : -size;
677 auto data = int_u.g_st().m_limbs.data();
680 std::fill(data + size, data + int_u.g_st().s_size, 0u);
683 int_u.g_st()._mp_size = 0;
684 std::fill(int_u.g_st().m_limbs.begin(), int_u.g_st().m_limbs.end(), 0u);
688 piranha::mpz_size_t sz;
690 const auto size = piranha::mp_integer_safe_abs_size(sz);
692 ::_mpz_realloc(&int_u.g_dy(),
static_cast<::mp_size_t
>(size));
694 std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + size,
696 int_u.g_dy()._mp_size = sz;
700 ::mpz_set_ui(&int_u.g_dy(), 0u);
707 template <
class Archive, std::size_t SSize,
708 piranha::enable_if_t<!std::is_same<Archive, boost::archive::binary_oarchive>::value,
int> = 0>
714 PIRANHA_MAYBE_TLS std::vector<char> tmp_v;
716 PIRANHA_MAYBE_TLS std::string tmp_s;
717 tmp_s.assign(tmp_v.data());
721 template <
class Archive, std::size_t SSize,
722 piranha::enable_if_t<!std::is_same<Archive, boost::archive::binary_iarchive>::value,
int> = 0>
725 PIRANHA_MAYBE_TLS std::string tmp;
730 template <
class Archive, std::
size_t SSize>
733 split_free(ar, n, file_version);
741 inline namespace impl
744 template <
typename Archive>
745 using mp_integer_boost_save_enabler
746 = enable_if_t<conjunction<has_boost_save<Archive, std::string>, has_boost_save<Archive, mpz_size_t>,
747 has_boost_save<Archive, bool>, has_boost_save<Archive, ::mp_limb_t>>::value>;
749 template <
typename Archive>
750 using mp_integer_boost_load_enabler
751 = enable_if_t<conjunction<has_boost_load<Archive, std::string>, has_boost_load<Archive, mpz_size_t>,
752 has_boost_load<Archive, bool>, has_boost_load<Archive, ::mp_limb_t>>::value>;
770 template <
typename Archive, std::
size_t SSize>
789 template <
typename Archive, std::
size_t SSize>
794 #if defined(PIRANHA_WITH_MSGPACK) 796 inline namespace impl
800 template <
typename Stream>
801 using mp_integer_msgpack_pack_enabler = enable_if_t<
805 template <
typename T>
806 using mp_integer_msgpack_convert_enabler
809 has_safe_cast<mpz_size_t,
typename std::vector<msgpack::object>::size_type>>::value>;
821 template <
typename Stream, std::
size_t SSize>
852 const auto size = int_u.g_st()._mp_size;
854 const auto usize =
static_cast<std::uint32_t
>(size >= 0 ? size : -size);
859 std::for_each(int_u.g_st().m_limbs.data(), int_u.g_st().m_limbs.data() + usize,
862 const auto size = int_u.g_dy()._mp_size;
865 usize =
safe_cast<std::uint32_t>(mp_integer_safe_abs_size(size));
867 piranha_throw(std::overflow_error,
"the number of limbs is too large");
872 std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + usize,
879 PIRANHA_MAYBE_TLS std::vector<char> tmp_v;
881 PIRANHA_MAYBE_TLS std::string tmp_s;
882 tmp_s.assign(tmp_v.data());
900 template <
typename T>
925 PIRANHA_MAYBE_TLS std::array<msgpack::object, 3> vobj;
931 const auto n_s = n.is_static();
934 const bool pstatus = n.promote();
941 auto &int_u = n._get_union();
945 PIRANHA_MAYBE_TLS std::vector<msgpack::object> vlimbs;
947 vobj[2u].convert(vlimbs);
948 const auto size = vlimbs.size();
950 auto it = vlimbs.begin();
952 if (unlikely(size > std::size_t(int_u.g_st().s_size))) {
954 "cannot deserialize a static integer with " + std::to_string(vlimbs.size())
955 +
" limbs, the static size is " + std::to_string(int_u.g_st().s_size));
959 auto data = int_u.g_st().m_limbs.data();
961 std::for_each(data, data + size, [f, &it](::mp_limb_t &l) {
966 std::fill(data + size, data + int_u.g_st().s_size, 0u);
968 int_u.g_st()._mp_size =
static_cast<mpz_size_t
>(size_sign ?
static_cast<mpz_size_t
>(size)
969 : -static_cast<mpz_size_t>(size));
972 int_u.g_st()._mp_size = 0;
973 std::fill(int_u.g_st().m_limbs.begin(), int_u.g_st().m_limbs.end(), 0u);
981 if (unlikely(sz > detail::safe_abs_sint<mpz_size_t>::value)) {
982 throw std::overflow_error(
"");
985 piranha_throw(std::overflow_error,
"the number of limbs is too large");
987 ::_mpz_realloc(&int_u.g_dy(), sz);
989 std::for_each(int_u.g_dy()._mp_d, int_u.g_dy()._mp_d + sz, [f, &it](::mp_limb_t &l) {
993 int_u.g_dy()._mp_size =
static_cast<mpz_size_t
>(size_sign ? sz : -sz);
995 ::mpz_set_ui(&int_u.g_dy(), 0u);
1000 PIRANHA_MAYBE_TLS std::string tmp;
1009 inline namespace impl
1013 template <
typename To,
typename From>
1014 using mp_integer_safe_cast_enabler = enable_if_t<
1015 disjunction<conjunction<is_mp_integer<To>, std::is_floating_point<From>, std::is_constructible<To, From>>,
1016 conjunction<is_mp_integer<To>, std::is_integral<From>, std::is_constructible<To, From>>,
1017 conjunction<is_mp_integer<From>, std::is_integral<To>, std::is_constructible<To, From>>>::value>;
1031 template <
typename To,
typename From>
1034 template <
typename T>
1035 using float_enabler = enable_if_t<std::is_floating_point<T>::value,
int>;
1036 template <
typename T>
1037 using mp_int_enabler = enable_if_t<is_mp_integer<T>::value,
int>;
1038 template <
typename T>
1039 using int_enabler = enable_if_t<std::is_integral<T>::value,
int>;
1040 template <
typename T,
float_enabler<T> = 0>
1041 static To impl(
const T &f)
1043 if (unlikely(!std::isfinite(f))) {
1045 +
" cannot be converted to an arbitrary-precision integer");
1047 if (unlikely(f != std::trunc(f))) {
1050 +
" cannot be converted to an arbitrary-precision integer");
1054 template <
typename T, mp_
int_enabler<T> = 0>
1055 static To impl(
const T &n)
1059 }
catch (
const std::overflow_error &) {
1061 +
" cannot be converted to the type '" + detail::demangle<To>()
1062 +
"', as the conversion cannot preserve the original value");
1065 template <
typename T,
int_enabler<T> = 0>
1066 static To impl(
const T &n)
Default functor for the implementation of piranha::math::mul3().
auto gcd(const T &a, const U &b) -> decltype(gcd_impl< T, U >()(a, b))
GCD.
mp_integer< SSize > operator()(const mp_integer< SSize > &a, const T1 &b) const
Call operator, piranha::mp_integer - integral overload.
void boost_load(Archive &ar, T &x)
Load from Boost archive.
void operator()(mp_integer< SSize > &x, const mp_integer< SSize > &y, const mp_integer< SSize > &z) const
Call operator.
bool operator()(const mp_integer< SSize > &n) const
Call operator.
Default functor for the implementation of piranha::math::negate().
Multiprecision integer class.
mp_integer< SSize > operator()(const T1 &a, const mp_integer< SSize > &b) const
Call operator, integral - piranha::mp_integer overload.
bool is_zero() const
Test if the value is zero.
Default implementation of piranha::boost_load().
Default functor for the implementation of piranha::math::div3().
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object.
Default functor for the implementation of piranha::math::multiply_accumulate().
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
mp_integer< SSize > factorial(const mp_integer< SSize > &n)
Factorial.
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Default functor for the implementation of piranha::math::is_zero().
Implementation of piranha::boost_load() via the Boost API.
Default functor for the implementation of piranha::math::sin().
std::string to_string(int base=10) const
Conversion to string.
Default implementation of piranha::boost_save().
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
Default functor for the implementation of piranha::math::cos().
mppp_impl::integer_union< SSize > & _get_union()
Return a reference to the internal union.
void operator()(msgpack::packer< Stream > &p, const mp_integer< SSize > &n, msgpack_format f) const
Call operator.
void operator()(mp_integer< SSize > &out, const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator.
mp_integer< SSize > operator()(const mp_integer< SSize > &n) const
Call operator.
bool promote()
Promote to dynamic storage.
Detect the presence of piranha::msgpack_convert().
void operator()(T &n, const msgpack::object &o, msgpack_format f) const
Call operator.
mp_integer< SSize > operator()(const mp_integer< SSize > &n) const
Call operator.
Default functor for the implementation of piranha::math::ipow_subs().
Default functor for the implementation of piranha::math::add3().
Default functor for the implementation of piranha::msgpack_convert().
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Default functor for the implementation of piranha::math::sub3().
Default functor for the implementation of piranha::math::gcd3().
Default functor for the implementation of piranha::msgpack_pack().
msgpack_format
Serialization format for msgpack.
mpz_view get_mpz_view() const
Get an mpz_t view.
mp_integer & neg()
Negate in-place.
Default functor for the implementation of piranha::math::partial().
Default implementation of piranha::safe_cast().
mp_integer< SSize > operator()(const mp_integer< SSize > &a, const mp_integer< SSize > &b) const
Call operator, piranha::mp_integer - piranha::mp_integer overload.
Default functor for the implementation of piranha::math::gcd().
bool is_zero(const T &x)
Zero test.
Type trait to detect the presence of the integral power substitution method in keys.
Implementation of piranha::boost_save() via the Boost API.
bool is_static() const
Test for static storage.
bool operator()(const mp_integer< SSize > &n) const
Call 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().
To operator()(const From &x) const
Call operator.
mp_integer< SSize > operator()(const mp_integer< SSize > &n) const
Call operator.
Type trait to detect piranha::safe_cast().
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
static const bool value
Value of the type trait.
static const bool value
Value of the type trait.
Default functor for the implementation of piranha::math::abs().
mp_integer< SSize > operator()(const mp_integer< SSize > &, const std::string &) const
Call operator.
Type trait to detect the availability of the piranha::math::ipow_subs() function. ...
void operator()(mp_integer< SSize > &n) const
Call operator.
math_ipow_subs_t< T, U > ipow_subs(const T &x, const std::string &name, const integer &n, const U &y)
Substitution of integral power.
Exception to signal failure in piranha::safe_cast().
Default functor for the implementation of piranha::math::is_unitary().
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.