29 #ifndef PIRANHA_REAL_HPP 30 #define PIRANHA_REAL_HPP 34 #include <boost/lexical_cast.hpp> 44 #include <type_traits> 46 #include <piranha/binomial.hpp> 47 #include <piranha/config.hpp> 48 #include <piranha/detail/demangle.hpp> 49 #include <piranha/detail/mpfr.hpp> 50 #include <piranha/detail/real_fwd.hpp> 52 #include <piranha/is_cf.hpp> 53 #include <piranha/math.hpp> 54 #include <piranha/mp_integer.hpp> 55 #include <piranha/mp_rational.hpp> 56 #include <piranha/pow.hpp> 57 #include <piranha/s11n.hpp> 58 #include <piranha/safe_cast.hpp> 67 template <
typename =
int>
71 static const ::mpfr_rnd_t default_rnd = MPFR_RNDN;
75 static const ::mpfr_prec_t default_prec = 113;
79 const ::mpfr_rnd_t real_base<T>::default_rnd;
82 const ::mpfr_prec_t real_base<T>::default_prec;
86 struct is_real_interoperable_type
87 : disjunction<mppp::mppp_impl::is_supported_interop<T>, is_mp_integer<T>, is_mp_rational<T>> {
126 class real :
public real_base<>
129 template <
typename T>
130 using is_interoperable_type = is_real_interoperable_type<T>;
132 template <
typename T>
133 using generic_ctor_enabler =
typename std::enable_if<is_interoperable_type<T>::value,
int>::type;
135 template <
typename T>
136 using cast_enabler = generic_ctor_enabler<T>;
138 template <
typename T>
139 using generic_in_place_enabler
140 = enable_if_t<conjunction<is_interoperable_type<T>, negation<std::is_const<T>>>::value,
int>;
142 static void prec_check(const ::mpfr_prec_t &prec)
144 if (unlikely(prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX)) {
145 piranha_throw(std::invalid_argument,
"invalid significand precision requested");
148 static bool is_digit(
char c)
158 const char digits[] =
"0123456789";
159 return std::find(digits, digits + 10, c) != (digits + 10);
162 void construct_from_string(
const char *str, const ::mpfr_prec_t &prec)
165 ::mpfr_init2(m_value, prec);
166 const int retval = ::mpfr_set_str(m_value, str, 10, default_rnd);
167 if (unlikely(retval != 0)) {
168 ::mpfr_clear(m_value);
169 piranha_throw(std::invalid_argument,
"invalid string input for real");
174 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
175 void construct_from_generic(
const T &x)
177 ::mpfr_set_ld(m_value, static_cast<long double>(x), default_rnd);
179 template <
typename T, enable_if_t<conjunction<std::is_
integral<T>, std::is_
signed<T>>::value,
int> = 0>
180 void construct_from_generic(
const T &si)
182 ::mpfr_set_sj(m_value, static_cast<std::intmax_t>(si), default_rnd);
184 template <
typename T, enable_if_t<conjunction<std::is_
integral<T>, std::is_
unsigned<T>>::value,
int> = 0>
185 void construct_from_generic(
const T &ui)
187 ::mpfr_set_uj(m_value, static_cast<std::uintmax_t>(ui), default_rnd);
189 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
190 void construct_from_generic(
const T &n)
192 auto v = n.get_mpz_view();
193 ::mpfr_set_z(m_value, v, default_rnd);
195 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
196 void construct_from_generic(
const T &q)
198 auto v = q.get_mpq_view();
199 ::mpfr_set_q(m_value, v, default_rnd);
202 void assign_from_string(
const char *str)
204 piranha_assert(m_value->_mpfr_d);
205 const int retval = ::mpfr_set_str(m_value, str, 10, default_rnd);
208 ::mpfr_set_zero(m_value, 0);
209 piranha_throw(std::invalid_argument,
"invalid string input for real");
213 template <
typename T>
214 typename std::enable_if<std::is_same<T, bool>::value, T>::type
convert_to_impl()
const 216 return (
sign() != 0);
218 template <
typename T>
219 typename std::enable_if<is_mp_integer<T>::value, T>::type
convert_to_impl()
const 222 piranha_throw(std::overflow_error,
"cannot convert non-finite real to an integral value");
227 ::mpfr_get_z(&retval._get_union().g_dy(), m_value, MPFR_RNDZ);
231 template <
typename T>
232 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, T>::type
237 return static_cast<T
>(
static_cast<integer>(*this));
239 template <
typename T>
240 typename std::enable_if<std::is_floating_point<T>::value, T>::type
convert_to_impl()
const 243 if (std::numeric_limits<T>::has_quiet_NaN) {
244 return std::numeric_limits<T>::quiet_NaN();
246 piranha_throw(std::overflow_error,
"cannot convert NaN to floating-point type");
250 piranha_assert(
sign() != 0);
251 if (std::numeric_limits<T>::has_infinity &&
sign() > 0) {
252 return std::numeric_limits<T>::infinity();
253 }
else if (std::numeric_limits<T>::has_infinity &&
sign() < 0) {
254 return std::copysign(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::lowest());
256 piranha_throw(std::overflow_error,
"cannot convert infinity to floating-point type");
259 if (std::is_same<T, long double>::value) {
260 return static_cast<T
>(::mpfr_get_ld(m_value, default_rnd));
262 if (std::is_same<T, double>::value) {
263 return static_cast<T
>(::mpfr_get_d(m_value, default_rnd));
265 return static_cast<T
>(::mpfr_get_flt(m_value, default_rnd));
268 typedef std::unique_ptr<char, void (*)(char *)> smart_mpfr_str;
269 template <
typename T>
270 typename std::enable_if<is_mp_rational<T>::value, T>::type
convert_to_impl()
const 273 piranha_throw(std::overflow_error,
"cannot convert NaN to rational");
276 piranha_throw(std::overflow_error,
"cannot convert infinity to rational");
283 char *cptr = ::mpfr_get_str(
nullptr, &
exp, 10, 0, m_value, default_rnd);
284 if (unlikely(!cptr)) {
286 "error in conversion of real to rational: the call to the MPFR function failed");
288 smart_mpfr_str str_ptr(cptr, ::mpfr_free_str);
290 std::size_t digits = 0u;
291 for (; *cptr !=
'\0'; ++cptr) {
292 if (is_digit(*cptr)) {
297 piranha_throw(std::overflow_error,
"error in conversion of real to rational: invalid number of digits");
302 T retval(str_ptr.get());
304 retval *= T(1, 10).pow(digits);
305 retval *= T(10).pow(
exp);
308 piranha_throw(std::overflow_error,
"error in conversion of real to rational: exponent is too large");
320 ::mpfr_add(m_value, m_value, r.m_value, default_rnd);
323 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
324 real &in_place_add(
const T &q)
326 auto v = q.get_mpq_view();
327 ::mpfr_add_q(m_value, m_value, v, default_rnd);
330 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
331 real &in_place_add(
const T &n)
333 auto v = n.get_mpz_view();
334 ::mpfr_add_z(m_value, m_value, v, default_rnd);
338 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
339 real &in_place_add(
const T &n)
341 return in_place_add(
integer(n));
344 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
345 real &in_place_add(
const T &x)
358 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
359 static real binary_add(
const real &a,
const T &b)
365 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
366 static real binary_add(
const T &a,
const real &b)
368 return binary_add(b, a);
376 ::mpfr_sub(m_value, m_value, r.m_value, default_rnd);
379 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
380 real &in_place_sub(
const T &q)
382 auto v = q.get_mpq_view();
383 ::mpfr_sub_q(m_value, m_value, v, default_rnd);
386 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
387 real &in_place_sub(
const T &n)
389 auto v = n.get_mpz_view();
390 ::mpfr_sub_z(m_value, m_value, v, default_rnd);
393 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
394 real &in_place_sub(
const T &n)
396 return in_place_sub(
integer(n));
398 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
399 real &in_place_sub(
const T &x)
410 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
411 static real binary_sub(
const real &a,
const T &b)
417 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
418 static real binary_sub(
const T &a,
const real &b)
420 auto retval = binary_sub(b, a);
430 ::mpfr_mul(m_value, m_value, r.m_value, default_rnd);
433 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
434 real &in_place_mul(
const T &q)
436 auto v = q.get_mpq_view();
437 ::mpfr_mul_q(m_value, m_value, v, default_rnd);
440 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
441 real &in_place_mul(
const T &n)
443 auto v = n.get_mpz_view();
444 ::mpfr_mul_z(m_value, m_value, v, default_rnd);
447 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
448 real &in_place_mul(
const T &n)
450 return in_place_mul(
integer(n));
452 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
453 real &in_place_mul(
const T &x)
464 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
465 static real binary_mul(
const real &a,
const T &b)
471 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
472 static real binary_mul(
const T &a,
const real &b)
474 return binary_mul(b, a);
482 ::mpfr_div(m_value, m_value, r.m_value, default_rnd);
485 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
486 real &in_place_div(
const T &q)
488 auto v = q.get_mpq_view();
489 ::mpfr_div_q(m_value, m_value, v, default_rnd);
492 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
493 real &in_place_div(
const T &n)
495 auto v = n.get_mpz_view();
496 ::mpfr_div_z(m_value, m_value, v, default_rnd);
499 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
500 real &in_place_div(
const T &n)
502 return in_place_div(
integer(n));
504 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
505 real &in_place_div(
const T &x)
516 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
517 static real binary_div(
const real &a,
const T &b)
523 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
524 static real binary_div(
const T &a,
const real &b)
532 static bool binary_equality(
const real &r1,
const real &r2)
534 return (::mpfr_equal_p(r1.m_value, r2.m_value) != 0);
536 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
537 static bool binary_equality(
const real &r,
const T &n)
542 auto v = n.get_mpz_view();
543 return (::mpfr_cmp_z(r.m_value, v) == 0);
545 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
546 static bool binary_equality(
const real &r,
const T &q)
551 auto v = q.get_mpq_view();
552 return (::mpfr_cmp_q(r.m_value, v) == 0);
554 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
555 static bool binary_equality(
const real &r,
const T &n)
562 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
563 static bool binary_equality(
const real &r,
const T &x)
565 if (r.
is_nan() || std::isnan(x)) {
571 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
572 static bool binary_equality(
const T &x,
const real &r)
574 return binary_equality(r, x);
577 static bool binary_less_than(
const real &r1,
const real &r2)
579 return (::mpfr_less_p(r1.m_value, r2.m_value) != 0);
581 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
582 static bool binary_less_than(
const real &r,
const T &q)
584 auto v = q.get_mpq_view();
585 return (::mpfr_cmp_q(r.m_value, v) < 0);
587 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
588 static bool binary_less_than(
const real &r,
const T &n)
590 auto v = n.get_mpz_view();
591 return (::mpfr_cmp_z(r.m_value, v) < 0);
593 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
594 static bool binary_less_than(
const real &r,
const T &n)
598 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
599 static bool binary_less_than(
const real &r,
const T &x)
604 static bool binary_leq(
const real &r1,
const real &r2)
606 return (::mpfr_lessequal_p(r1.m_value, r2.m_value) != 0);
608 template <typename T, typename std::enable_if<is_mp_rational<T>::value,
int>::type = 0>
609 static bool binary_leq(
const real &r,
const T &q)
611 auto v = q.get_mpq_view();
612 return (::mpfr_cmp_q(r.m_value, v) <= 0);
614 template <typename T, typename std::enable_if<is_mp_integer<T>::value,
int>::type = 0>
615 static bool binary_leq(
const real &r,
const T &n)
617 auto v = n.get_mpz_view();
618 return (::mpfr_cmp_z(r.m_value, v) <= 0);
620 template <typename T, typename std::enable_if<std::is_integral<T>::value,
int>::type = 0>
621 static bool binary_leq(
const real &r,
const T &n)
625 template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
int>::type = 0>
626 static bool binary_leq(
const real &r,
const T &x)
631 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
632 static bool binary_less_than(
const T &x,
const real &r)
634 return !binary_leq(r, x);
636 template <typename T, typename std::enable_if<is_interoperable_type<T>::value,
int>::type = 0>
637 static bool binary_leq(
const T &x,
const real &r)
639 return !binary_less_than(r, x);
643 static bool check_nan(
const real &r)
647 template <
typename T>
648 static bool check_nan(
const T &x,
typename std::enable_if<std::is_floating_point<T>::value>::type * =
nullptr)
650 return std::isnan(x);
652 template <
typename T>
653 static bool check_nan(
const T &,
typename std::enable_if<!std::is_floating_point<T>::value>::type * =
nullptr)
657 template <
typename T,
typename U>
658 static bool is_nan_comparison(
const T &a,
const U &b)
660 return (check_nan(a) || check_nan(b));
663 friend class boost::serialization::access;
665 static ::mpfr_prec_t size_from_prec(::mpfr_prec_t prec)
667 const ::mpfr_prec_t q = prec / ::mp_bits_per_limb, r = prec % ::mp_bits_per_limb;
671 template <class Archive, enable_if_t<!std::is_same<Archive, boost::archive::binary_oarchive>::value,
int> = 0>
672 void save(Archive &ar,
unsigned)
const 675 std::ostringstream oss;
682 template <class Archive, enable_if_t<!std::is_same<Archive, boost::archive::binary_iarchive>::value,
int> = 0>
683 void load(Archive &ar,
unsigned)
686 PIRANHA_MAYBE_TLS std::string s;
689 *
this =
real(s, prec);
692 template <class Archive, enable_if_t<std::is_same<Archive, boost::archive::binary_oarchive>::value,
int> = 0>
693 void save(Archive &ar,
unsigned)
const 698 const ::mpfr_prec_t s = size_from_prec(m_value->_mpfr_prec);
700 for (::mpfr_prec_t i = 0; i < s; ++i) {
704 template <class Archive, enable_if_t<std::is_same<Archive, boost::archive::binary_iarchive>::value,
int> = 0>
705 void load(Archive &ar,
unsigned)
709 decltype(m_value->_mpfr_sign)
sign;
710 decltype(m_value->_mpfr_exp)
exp;
715 const ::mpfr_prec_t s = size_from_prec(prec);
718 piranha_assert(m_value->_mpfr_prec == prec);
719 m_value->_mpfr_sign =
sign;
720 m_value->_mpfr_exp =
exp;
725 for (::mpfr_prec_t i = 0; i < s; ++i) {
730 ::mpfr_set_ui(m_value, 0u, default_rnd);
734 BOOST_SERIALIZATION_SPLIT_MEMBER()
742 ::mpfr_init2(m_value, default_prec);
743 ::mpfr_set_zero(m_value, 0);
754 ::mpfr_init2(m_value, other.
get_prec());
755 ::mpfr_set(m_value, other.m_value, default_rnd);
763 m_value->_mpfr_prec = other.m_value->_mpfr_prec;
764 m_value->_mpfr_sign = other.m_value->_mpfr_sign;
765 m_value->_mpfr_exp = other.m_value->_mpfr_exp;
766 m_value->_mpfr_d = other.m_value->_mpfr_d;
768 other.m_value->_mpfr_prec = 0;
769 other.m_value->_mpfr_sign = 0;
770 other.m_value->_mpfr_exp = 0;
771 other.m_value->_mpfr_d =
nullptr;
784 explicit real(
const char *str, const ::mpfr_prec_t &prec = default_prec)
786 construct_from_string(str, prec);
797 explicit real(
const std::string &str, const ::mpfr_prec_t &prec = default_prec)
799 construct_from_string(str.c_str(), prec);
811 explicit real(
const real &other, const ::mpfr_prec_t &prec)
814 ::mpfr_init2(m_value, prec);
815 ::mpfr_set(m_value, other.m_value, default_rnd);
828 template <
typename T,
typename =
generic_ctor_enabler<T>>
829 explicit real(
const T &x, const ::mpfr_prec_t &prec = default_prec)
832 ::mpfr_init2(m_value, prec);
833 construct_from_generic(x);
850 if (
this != &other) {
852 if (m_value->_mpfr_d) {
856 piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
858 ::mpfr_init2(m_value, other.
get_prec());
860 ::mpfr_set(m_value, other.m_value, default_rnd);
908 if (m_value->_mpfr_d) {
909 assign_from_string(str);
911 piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
912 construct_from_string(str, default_prec);
930 template <
typename T,
typename =
generic_ctor_enabler<T>>
933 if (!m_value->_mpfr_d) {
934 piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
936 ::mpfr_init2(m_value, default_prec);
939 construct_from_generic(x);
965 template <
typename T,
typename = cast_enabler<T>>
966 explicit operator T()
const 978 if (
this == &other) {
981 ::mpfr_swap(m_value, other.m_value);
993 return mpfr_sgn(m_value);
1002 return (mpfr_zero_p(m_value) != 0);
1010 return mpfr_nan_p(m_value) != 0;
1018 return mpfr_inf_p(m_value) != 0;
1026 return mpfr_get_prec(m_value);
1040 ::mpfr_set_prec(m_value, prec);
1048 ::mpfr_neg(m_value, m_value, default_rnd);
1060 ::mpfr_trunc(m_value, m_value);
1088 template <
typename T>
1091 return in_place_add(x);
1109 template <
typename T,
generic_in_place_enabler<T> = 0>
1113 return x =
static_cast<T
>(r + x);
1132 template <
typename T,
typename U>
1133 friend auto operator+(
const T &x,
const U &y) -> decltype(real::binary_add(x, y))
1135 return binary_add(x, y);
1163 const real retval(*
this);
1183 template <
typename T>
1186 return in_place_sub(x);
1204 template <
typename T,
generic_in_place_enabler<T> = 0>
1207 return x =
static_cast<T
>(x - r);
1226 template <
typename T,
typename U>
1227 friend auto operator-(
const T &x,
const U &y) -> decltype(real::binary_sub(x, y))
1229 return binary_sub(x, y);
1259 const real retval(*
this);
1279 template <
typename T>
1282 return in_place_mul(x);
1300 template <
typename T,
generic_in_place_enabler<T> = 0>
1303 return x =
static_cast<T
>(x * r);
1322 template <
typename T,
typename U>
1323 friend auto operator*(
const T &x,
const U &y) -> decltype(real::binary_mul(x, y))
1325 return binary_mul(x, y);
1343 template <
typename T>
1346 return in_place_div(x);
1364 template <
typename T,
generic_in_place_enabler<T> = 0>
1367 return x =
static_cast<T
>(x / r);
1386 template <
typename T,
typename U>
1387 friend auto operator/(
const T &x,
const U &y) -> decltype(real::binary_div(x, y))
1389 return binary_div(x, y);
1404 const ::mpfr_prec_t prec1 = std::max<::mpfr_prec_t>(r1.
get_prec(), r2.
get_prec());
1406 *
this =
real{*
this, prec1};
1413 #if defined(PIRANHA_HAVE_THREAD_LOCAL) 1414 static thread_local
real tmp;
1418 ::mpfr_set_prec(tmp.m_value, mpfr_get_prec(m_value));
1419 ::mpfr_mul(tmp.m_value, r1.m_value, r2.m_value, MPFR_RNDN);
1420 ::mpfr_add(m_value, m_value, tmp.m_value, MPFR_RNDN);
1422 ::mpfr_fma(m_value, r1.m_value, r2.m_value, m_value, default_rnd);
1442 template <
typename T,
typename U>
1443 friend auto operator==(
const T &x,
const U &y) -> decltype(real::binary_equality(x, y))
1445 return binary_equality(x, y);
1463 template <
typename T,
typename U>
1464 friend auto operator!=(
const T &x,
const U &y) -> decltype(!real::binary_equality(x, y))
1466 return !binary_equality(x, y);
1484 template <
typename T,
typename U>
1485 friend auto operator<(
const T &x,
const U &y) -> decltype(real::binary_less_than(x, y))
1487 if (is_nan_comparison(x, y)) {
1490 return binary_less_than(x, y);
1508 template <
typename T,
typename U>
1509 friend auto operator<=(
const T &x,
const U &y) -> decltype(real::binary_leq(x, y))
1511 if (is_nan_comparison(x, y)) {
1514 return binary_leq(x, y);
1532 template <
typename T,
typename U>
1533 friend auto operator>(
const T &x,
const U &y) -> decltype(real::binary_less_than(y, x))
1535 if (is_nan_comparison(x, y)) {
1556 template <
typename T,
typename U>
1557 friend auto operator>=(
const T &x,
const U &y) -> decltype(real::binary_leq(y, x))
1559 if (is_nan_comparison(x, y)) {
1578 ::mpfr_pow(retval.m_value, m_value,
exp.m_value, default_rnd);
1588 ::mpfr_gamma(retval.m_value, m_value, default_rnd);
1600 ::mpfr_lgamma(retval.m_value, &
sign, m_value, default_rnd);
1610 ::mpfr_exp(retval.m_value, m_value, default_rnd);
1621 ::mpfr_abs(retval.m_value, retval.m_value, default_rnd);
1631 ::mpfr_sin(retval.m_value, m_value, default_rnd);
1641 ::mpfr_cos(retval.m_value, m_value, default_rnd);
1651 ::mpfr_const_pi(retval.m_value, default_rnd);
1685 ::mpfr_exp_t
exp(0);
1686 char *cptr = ::mpfr_get_str(
nullptr, &
exp, 10, 0, r.m_value, default_rnd);
1687 if (unlikely(!cptr)) {
1689 "error in conversion of real to rational: the call to the MPFR function failed");
1691 smart_mpfr_str str(cptr, ::mpfr_free_str);
1693 std::string cpp_str(str.get());
1695 auto it = std::find_if(cpp_str.begin(), cpp_str.end(), is_digit);
1696 if (it != cpp_str.end()) {
1698 cpp_str.insert(it,
'.');
1699 if (
exp == std::numeric_limits<::mpfr_exp_t>::min()) {
1700 piranha_throw(std::overflow_error,
"overflow in conversion of real to string");
1703 if (
exp != ::mpfr_exp_t(0) && r.
sign() != 0) {
1704 cpp_str.append(
"e" + boost::lexical_cast<std::string>(
exp));
1723 std::string tmp_str;
1724 std::getline(is, tmp_str);
1733 std::remove_extent<::mpfr_t>::type *
get_mpfr_t()
1736 return &m_value[0u];
1741 return &m_value[0u];
1745 #if defined(PIRANHA_WITH_MSGPACK) 1748 template <
typename Stream>
1749 using msgpack_pack_enabler
1757 template <
typename U>
1758 using msgpack_convert_enabler
1759 = enable_if_t<conjunction<std::is_same<U, U>,
1789 template <
typename Stream, msgpack_pack_enabler<Stream> = 0>
1793 std::ostringstream oss;
1808 const auto s =
safe_cast<std::uint32_t>(size_from_prec(m_value->_mpfr_prec));
1811 for (std::uint32_t i = 0; i < s; ++i) {
1840 template <
typename U = real, msgpack_convert_enabler<U> = 0>
1844 PIRANHA_MAYBE_TLS std::array<msgpack::object, 2> vobj;
1847 PIRANHA_MAYBE_TLS std::string s;
1850 *
this =
real(s, prec);
1852 PIRANHA_MAYBE_TLS std::array<msgpack::object, 4> vobj;
1856 decltype(m_value->_mpfr_sign)
sign;
1857 decltype(m_value->_mpfr_exp)
exp;
1862 piranha_assert(m_value->_mpfr_prec == prec);
1863 m_value->_mpfr_sign =
sign;
1864 m_value->_mpfr_exp =
exp;
1868 PIRANHA_MAYBE_TLS std::vector<msgpack::object> vlimbs;
1869 vobj[3].convert(vlimbs);
1870 const auto s =
safe_cast<std::vector<msgpack::object>::size_type>(size_from_prec(prec));
1871 if (unlikely(s != vlimbs.size())) {
1873 std::string(
"error in the msgpack deserialization of a real: the number " 1874 "of serialized limbs (")
1875 + std::to_string(vlimbs.size())
1876 +
") is not consistent with the number of limbs inferred from the precision (" 1877 + std::to_string(s) +
")");
1879 for (decltype(vlimbs.size()) i = 0; i < s; ++i) {
1884 ::mpfr_set_ui(m_value, 0u, default_rnd);
1899 template <
typename T>
1912 template <
typename T>
1931 template <
typename T,
typename U>
1932 using real_pow_enabler =
1933 typename std::enable_if<(std::is_same<real, T>::value && is_real_interoperable_type<U>::value)
1934 || (std::is_same<real, U>::value && is_real_interoperable_type<T>::value)
1935 || (std::is_same<real, T>::value && std::is_same<real, U>::value)>::type;
1938 template <
typename T,
typename U>
1939 using real_binomial_enabler = real_pow_enabler<T, U>;
1955 template <
typename T,
typename U>
1956 struct pow_impl<T, U, detail::real_pow_enabler<T, U>> {
1980 template <
typename T2>
1997 template <
typename T2>
2000 return real{r, x.get_prec()}.pow(x);
2005 template <
typename T>
2006 struct sin_impl<T, typename
std::enable_if<std::is_same<T, real>::value>::type> {
2022 template <
typename T>
2023 struct cos_impl<T, typename
std::enable_if<std::is_same<T, real>::value>::type> {
2039 template <
typename T>
2040 struct abs_impl<T, typename
std::enable_if<std::is_same<T, real>::value>::type> {
2054 template <
typename T>
2076 template <
typename T,
typename U>
2089 return x.binomial(y);
2101 template <
typename T2>
2106 return x.binomial(
real{y, x.get_prec()});
2118 template <
typename T2>
2138 x.multiply_accumulate(y, z);
2146 static_assert(default_prec >= MPFR_PREC_MIN && default_prec <= MPFR_PREC_MAX,
2147 "Invalid value for default precision.");
2148 if (m_value->_mpfr_d) {
2149 ::mpfr_clear(m_value);
2156 #if !defined(PIRANHA_COMPILER_IS_INTEL) 2157 piranha_assert(!m_value->_mpfr_prec);
2158 piranha_assert(!m_value->_mpfr_sign);
2159 piranha_assert(!m_value->_mpfr_exp);
2169 inline real real_compute_3_gamma(
const real &a,
const real &b,
const real &c, const ::mpfr_prec_t &prec)
2176 real tmp0(0), tmp1(1);
2178 tmp0 -= (1 - a).lgamma();
2179 tmp1 *= pi / (a * pi).sin();
2184 tmp0 += (1 - b).lgamma();
2185 tmp1 *= (b * pi).
sin() / pi;
2190 tmp0 += (1 - c).lgamma();
2191 tmp1 *= (c * pi).
sin() / pi;
2195 return tmp0.
exp() * tmp1;
2217 piranha_throw(std::invalid_argument,
"cannot compute binomial coefficient with non-finite real argument(s)");
2220 const ::mpfr_prec_t max_prec = std::max<::mpfr_prec_t>(
get_prec(), y.
get_prec());
2222 neg_int_x_y = ((*this) - y).
truncated() == ((*this) - y) && ((*
this) - y).
sign() < 0;
2223 const unsigned mask = unsigned(neg_int_x) + (unsigned(neg_int_y) << 1u) + (
unsigned(neg_int_x_y) << 2u);
2227 return detail::real_compute_3_gamma((*
this) + 1, y + 1, (*
this) - y + 1, max_prec);
2232 return real{0, max_prec};
2241 return detail::real_compute_3_gamma(-y, -(*
this), (*
this) - y + 1, max_prec) * phase;
2245 return detail::real_compute_3_gamma(-((*
this) - y), y + 1, -(*
this), max_prec) * phase;
2250 return real{0, max_prec};
2253 inline namespace impl
2256 template <
typename To,
typename From>
2257 using sc_real_enabler
2258 = enable_if_t<conjunction<disjunction<std::is_integral<To>, is_mp_integer<To>, is_mp_rational<To>>,
2259 std::is_same<From, real>>::value>;
2268 template <
typename To,
typename From>
2271 template <
typename T>
2272 using integral_enabler = enable_if_t<disjunction<std::is_integral<T>, is_mp_integer<T>>::value,
int>;
2273 template <
typename T>
2274 using rational_enabler = enable_if_t<is_mp_rational<T>::value,
int>;
2292 template <
typename T = To,
integral_enabler<T> = 0>
2299 +
" to the integral type '" + detail::demangle<To>()
2300 +
"', as the input real does not represent a finite integral value");
2303 return static_cast<T
>(r);
2304 }
catch (
const std::overflow_error &) {
2306 +
" to the integral type '" + detail::demangle<To>()
2307 +
"', as the conversion would not preserve the value");
2322 template <
typename T = To, rational_enabler<T> = 0>
2326 return static_cast<T
>(r);
2327 }
catch (
const std::overflow_error &) {
2329 +
" to the rational type '" + detail::demangle<To>()
2330 +
"', as the conversion would not preserve the value");
2335 inline namespace literals
2349 inline real operator"" _r(
const char *s)
2355 inline namespace impl
2358 template <
typename Archive>
2359 using real_boost_save_enabler
2360 = enable_if_t<conjunction<has_boost_save<Archive, ::mpfr_prec_t>, has_boost_save<Archive, std::string>,
2361 has_boost_save<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_sign)>,
2362 has_boost_save<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_exp)>,
2363 has_boost_save<Archive, ::mp_limb_t>>::value>;
2365 template <
typename Archive>
2366 using real_boost_load_enabler
2367 = enable_if_t<conjunction<has_boost_load<Archive, ::mpfr_prec_t>, has_boost_load<Archive, std::string>,
2368 has_boost_load<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_sign)>,
2369 has_boost_load<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_exp)>,
2370 has_boost_load<Archive, ::mp_limb_t>>::value>;
2385 template <
typename Archive>
2401 template <
typename Archive>
2405 #if defined(PIRANHA_WITH_MSGPACK) 2407 inline namespace impl
2411 template <
typename Stream>
2412 using real_msgpack_pack_enabler = enable_if_t<is_detected<msgpack_pack_member_t, Stream, real>::value>;
2414 template <
typename T>
2415 using real_msgpack_convert_enabler
2416 = enable_if_t<conjunction<std::is_same<real, T>, is_detected<msgpack_convert_member_t, T>>::value>;
2425 template <
typename Stream>
2439 x.msgpack_pack(p, f);
2449 template <
typename T>
2463 x.msgpack_convert(o, f);
2469 inline namespace impl
2472 template <
typename T>
2473 using real_zero_is_absorbing_enabler = enable_if_t<std::is_same<uncvref_t<T>, real>::value>;
2483 template <
typename T>
2489 template <
typename T>
math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation.
real operator()(const T2 &x, const real &y) const
Call operator, real bottom overload.
void swap(real &other)
Swap.
friend std::ostream & operator<<(std::ostream &os, const real &r)
Overload output stream operator for piranha::real.
void msgpack_pack(msgpack::packer< Stream > &p, msgpack_format f) const
Pack in msgpack format.
void boost_load(Archive &ar, T &x)
Load from Boost archive.
Default functor for the implementation of piranha::math::negate().
Multiprecision integer class.
friend auto operator<=(const T &x, const U &y) -> decltype(real::binary_leq(x, y))
Generic less-than or equal operator involving piranha::real.
void operator()(msgpack::packer< Stream > &p, const real &x, msgpack_format f) const
Call operator.
Default implementation of piranha::boost_load().
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
real lgamma() const
Logarithm of the gamma function.
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().
bool is_nan() const
Test for NaN.
void truncate()
Truncate in-place.
real & operator=(const std::string &str)
Assignment operator from C++ string.
Type trait to detect coefficient types.
friend auto operator!=(const T &x, const U &y) -> decltype(!real::binary_equality(x, y))
Generic inequality operator involving piranha::real.
real pow(const real &exp) const
Exponentiation.
void operator()(T &x, const msgpack::object &o, msgpack_format f) const
Call operator.
Default functor for the implementation of piranha::math::binomial().
real & operator=(const char *str)
Assignment operator from C string.
Default functor for the implementation of piranha::math::is_zero().
Implementation of piranha::boost_load() via the Boost API.
friend auto operator-(const T &x, const U &y) -> decltype(real::binary_sub(x, y))
Generic binary subtraction involving piranha::real.
Default functor for the implementation of piranha::math::sin().
real(const T &x, const ::mpfr_prec_t &prec=default_prec)
Generic constructor.
Default implementation of piranha::boost_save().
Default functor for the implementation of piranha::math::cos().
Arbitrary precision floating-point class.
real(const real &other, const ::mpfr_prec_t &prec)
Copy constructor with different precision.
Default functor for the implementation of piranha::math::pow().
friend auto operator>(const T &x, const U &y) -> decltype(real::binary_less_than(y, x))
Generic greater-than operator involving piranha::real.
real(const char *str, const ::mpfr_prec_t &prec=default_prec)
Constructor from C string.
auto operator-=(const T &x) -> decltype(this->in_place_sub(x))
In-place subtraction.
real operator()(const real &x, const real &y) const
Call operator, real–real overload.
real operator()(const real &r, const T2 &x) const
Call operator, real base overload.
Detect the presence of piranha::msgpack_convert().
auto operator+=(const T &x) -> decltype(this->in_place_add(x))
In-place addition.
friend auto operator>=(const T &x, const U &y) -> decltype(real::binary_leq(y, x))
Generic greater-than or equal operator involving piranha::real.
real operator()(const real &x, const T2 &y) const
Call operator, real top overload.
friend auto operator<(const T &x, const U &y) -> decltype(real::binary_less_than(x, y))
Generic less-than operator involving piranha::real.
real operator()(const real &r, const real &x) const
Call operator, real–real overload.
void negate()
Negate in-place.
Default functor for the implementation of piranha::msgpack_convert().
real operator()(const T &r) const
Call operator.
real & operator=(const real &other)
Copy assignment operator.
real & operator++()
Prefix increment.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
bool is_inf() const
Test for infinity.
Default functor for the implementation of piranha::msgpack_pack().
real(const real &other)
Copy constructor.
msgpack_format
Serialization format for msgpack.
Detect if zero is a multiplicative absorber.
Default functor for the implementation of piranha::math::partial().
real truncated() const
Truncated copy.
Default implementation of piranha::safe_cast().
real & multiply_accumulate(const real &r1, const real &r2)
Combined multiply-add.
Default functor for the implementation of piranha::convert_to().
friend auto operator*(const T &x, const U &y) -> decltype(real::binary_mul(x, y))
Generic binary multiplication involving piranha::real.
real operator()(const real &, const std::string &) const
Call operator.
real pi() const
Pi constant.
Implementation of piranha::boost_save() via the Boost API.
void set_prec(const ::mpfr_prec_t &prec)
Set precision.
auto operator*=(const T &x) -> decltype(this->in_place_mul(x))
In-place multiplication.
real(const std::string &str, const ::mpfr_prec_t &prec=default_prec)
Constructor from C++ string.
friend T & operator+=(T &x, const real &r)
Generic in-place addition with piranha::real.
real exp() const
Exponential.
friend T & operator-=(T &x, const real &r)
Generic in-place subtraction with piranha::real.
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
real & operator=(real &&other) noexcept
Move assignment operator.
::mpfr_prec_t get_prec() const
Get precision.
real operator--(int)
Suffix decrement.
bool operator()(const T &r) const
Call operator.
Detect the presence of piranha::msgpack_pack().
const std::remove_extent<::mpfr_t >::type * get_mpfr_t() const
Get a const reference to the internal mpfr_t instance.
friend T & operator*=(T &x, const real &r)
Generic in-place multiplication by piranha::real.
real(real &&other) noexcept
Move constructor.
real operator()(const T &r) const
Call operator.
void operator()(real &x) const
Call operator.
real operator-() const
Negated copy.
friend T & operator/=(T &x, const real &r)
Generic in-place division by piranha::real.
real binomial(const real &) const
Binomial coefficient.
void operator()(real &x, const real &y, const real &z) const
Call operator.
auto operator/=(const T &x) -> decltype(this->in_place_div(x))
In-place division.
real()
Default constructor.
friend auto operator==(const T &x, const U &y) -> decltype(real::binary_equality(x, y))
Generic equality operator involving piranha::real.
T operator()(const T &x) const
Call operator.
Type trait to detect piranha::safe_cast().
std::remove_extent<::mpfr_t >::type * get_mpfr_t()
Get a mutable reference to the internal mpfr_t instance.
real operator+() const
Identity operator.
real & operator=(const T &x)
Generic assignment operator.
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
bool is_zero() const
Test for zero.
friend auto operator/(const T &x, const U &y) -> decltype(real::binary_div(x, y))
Generic binary division involving piranha::real.
real gamma() const
Gamma function.
T operator()(const real &r) const
Call operator, real to integral overload.
friend auto operator+(const T &x, const U &y) -> decltype(real::binary_add(x, y))
Generic binary addition involving piranha::real.
real operator()(const T2 &r, const real &x) const
Call operator, real exponent overload.
static const bool value
Value of the type trait.
void msgpack_convert(const msgpack::object &o, msgpack_format f)
Convert from msgpack object.
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
Default functor for the implementation of piranha::math::abs().
friend std::istream & operator>>(std::istream &is, real &r)
Overload input stream operator for piranha::real.
real & operator--()
Prefix decrement.
Exception to signal failure in piranha::safe_cast().
detail::math_sin_type< T > sin(const T &x)
Sine.
real abs() const
Absolute value.
real operator++(int)
Suffix increment.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.