piranha  0.10
real.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_REAL_HPP
30 #define PIRANHA_REAL_HPP
31 
32 #include <algorithm>
33 #include <array>
34 #include <boost/lexical_cast.hpp>
35 #include <cmath>
36 #include <cstddef>
37 #include <cstdint>
38 #include <iostream>
39 #include <limits>
40 #include <memory>
41 #include <sstream>
42 #include <stdexcept>
43 #include <string>
44 #include <type_traits>
45 
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>
51 #include <piranha/exceptions.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>
59 #include <piranha/type_traits.hpp>
60 
61 namespace piranha
62 {
63 
64 inline namespace impl
65 {
66 
67 template <typename = int>
68 struct real_base {
69  // Default rounding mode.
70  // All operations will use the MPFR_RNDN (round to nearest) rounding mode.
71  static const ::mpfr_rnd_t default_rnd = MPFR_RNDN;
72  // Default significand precision.
73  // The precision is the number of bits used to represent the significand of a floating-point number.
74  // This default value is equivalent to the IEEE 754 quadruple-precision binary floating-point format.
75  static const ::mpfr_prec_t default_prec = 113;
76 };
77 
78 template <typename T>
79 const ::mpfr_rnd_t real_base<T>::default_rnd;
80 
81 template <typename T>
82 const ::mpfr_prec_t real_base<T>::default_prec;
83 
84 // Types interoperable with real.
85 template <typename T>
86 struct is_real_interoperable_type
87  : disjunction<mppp::mppp_impl::is_supported_interop<T>, is_mp_integer<T>, is_mp_rational<T>> {
88 };
89 }
90 
92 
116 // NOTES:
117 // - if we overhaul the tests, put random precision values as well.
118 // - maybe we should have a setter as well for the global default precision. It would need to be an atomic
119 // variable, and we need perf measures to understand the performance impact of this.
120 // - For series evaluation, we need to be careful performance-wise with the possible conversions that might go
121 // on when mixing real with other types. E.g., pow(real,int) when evaluating polynomials. We need to make sure
122 // the conversions are as fast as possible.
123 // - At the moment, this class is technically not sortable because moved-from reals cannot be compared. For use in
124 // std::sort, we should add special casing for moved-from objects. See:
125 // http://stackoverflow.com/questions/26579132/what-is-the-post-condition-of-a-move-constructor
126 class real : public real_base<>
127 {
128  // Shortcut for interop type detector.
129  template <typename T>
130  using is_interoperable_type = is_real_interoperable_type<T>;
131  // Enabler for generic ctor.
132  template <typename T>
133  using generic_ctor_enabler = typename std::enable_if<is_interoperable_type<T>::value, int>::type;
134  // Enabler for conversion operator.
135  template <typename T>
136  using cast_enabler = generic_ctor_enabler<T>;
137  // Enabler for in-place arithmetic operations with interop on the left.
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>;
141  // Precision check.
142  static void prec_check(const ::mpfr_prec_t &prec)
143  {
144  if (unlikely(prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX)) {
145  piranha_throw(std::invalid_argument, "invalid significand precision requested");
146  }
147  }
148  static bool is_digit(char c)
149  {
150  // NOTE: check this answer:
151  // http://stackoverflow.com/questions/13827180/char-ascii-relation
152  // """
153  // The mapping of integer values for characters does have one guarantee given
154  // by the Standard: the values of the decimal digits are continguous.
155  // (i.e., '1' - '0' == 1, ... '9' - '0' == 9)
156  // """
157  // It should be possible to implement this with a binary search.
158  const char digits[] = "0123456789";
159  return std::find(digits, digits + 10, c) != (digits + 10);
160  }
161  // Construction.
162  void construct_from_string(const char *str, const ::mpfr_prec_t &prec)
163  {
164  prec_check(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");
170  }
171  }
172  // The idea here is that we use the largest integral and fp types supported by the MPFR api for construction,
173  // and down-cast as needed.
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)
176  {
177  ::mpfr_set_ld(m_value, static_cast<long double>(x), default_rnd);
178  }
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)
181  {
182  ::mpfr_set_sj(m_value, static_cast<std::intmax_t>(si), default_rnd);
183  }
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)
186  {
187  ::mpfr_set_uj(m_value, static_cast<std::uintmax_t>(ui), default_rnd);
188  }
189  template <typename T, typename std::enable_if<is_mp_integer<T>::value, int>::type = 0>
190  void construct_from_generic(const T &n)
191  {
192  auto v = n.get_mpz_view();
193  ::mpfr_set_z(m_value, v, default_rnd);
194  }
195  template <typename T, typename std::enable_if<is_mp_rational<T>::value, int>::type = 0>
196  void construct_from_generic(const T &q)
197  {
198  auto v = q.get_mpq_view();
199  ::mpfr_set_q(m_value, v, default_rnd);
200  }
201  // Assignment.
202  void assign_from_string(const char *str)
203  {
204  piranha_assert(m_value->_mpfr_d);
205  const int retval = ::mpfr_set_str(m_value, str, 10, default_rnd);
206  if (retval != 0) {
207  // Reset the internal value, as it might have been changed by ::mpfr_set_str().
208  ::mpfr_set_zero(m_value, 0);
209  piranha_throw(std::invalid_argument, "invalid string input for real");
210  }
211  }
212  // Conversion.
213  template <typename T>
214  typename std::enable_if<std::is_same<T, bool>::value, T>::type convert_to_impl() const
215  {
216  return (sign() != 0);
217  }
218  template <typename T>
219  typename std::enable_if<is_mp_integer<T>::value, T>::type convert_to_impl() const
220  {
221  if (is_nan() || is_inf()) {
222  piranha_throw(std::overflow_error, "cannot convert non-finite real to an integral value");
223  }
224  T retval;
225  retval.promote();
226  // Explicitly request rounding to zero in this case.
227  ::mpfr_get_z(&retval._get_union().g_dy(), m_value, MPFR_RNDZ);
228  // NOTE: demote candidate.
229  return retval;
230  }
231  template <typename T>
232  typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, T>::type
233  convert_to_impl() const
234  {
235  // NOTE: of course, this can be optimised by avoiding going through the integer conversion and
236  // using directly the MPFR functions.
237  return static_cast<T>(static_cast<integer>(*this));
238  }
239  template <typename T>
240  typename std::enable_if<std::is_floating_point<T>::value, T>::type convert_to_impl() const
241  {
242  if (is_nan()) {
243  if (std::numeric_limits<T>::has_quiet_NaN) {
244  return std::numeric_limits<T>::quiet_NaN();
245  } else {
246  piranha_throw(std::overflow_error, "cannot convert NaN to floating-point type");
247  }
248  }
249  if (is_inf()) {
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());
255  } else {
256  piranha_throw(std::overflow_error, "cannot convert infinity to floating-point type");
257  }
258  }
259  if (std::is_same<T, long double>::value) {
260  return static_cast<T>(::mpfr_get_ld(m_value, default_rnd));
261  }
262  if (std::is_same<T, double>::value) {
263  return static_cast<T>(::mpfr_get_d(m_value, default_rnd));
264  }
265  return static_cast<T>(::mpfr_get_flt(m_value, default_rnd));
266  }
267  // Smart pointer to handle the string output from mpfr.
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
271  {
272  if (is_nan()) {
273  piranha_throw(std::overflow_error, "cannot convert NaN to rational");
274  }
275  if (is_inf()) {
276  piranha_throw(std::overflow_error, "cannot convert infinity to rational");
277  }
278  if (sign() == 0) {
279  return T{};
280  }
281  // Get string representation.
282  ::mpfr_exp_t exp(0);
283  char *cptr = ::mpfr_get_str(nullptr, &exp, 10, 0, m_value, default_rnd);
284  if (unlikely(!cptr)) {
285  piranha_throw(std::overflow_error,
286  "error in conversion of real to rational: the call to the MPFR function failed");
287  }
288  smart_mpfr_str str_ptr(cptr, ::mpfr_free_str);
289  // Transform into fraction.
290  std::size_t digits = 0u;
291  for (; *cptr != '\0'; ++cptr) {
292  if (is_digit(*cptr)) {
293  ++digits;
294  }
295  }
296  if (!digits) {
297  piranha_throw(std::overflow_error, "error in conversion of real to rational: invalid number of digits");
298  }
299  // NOTE: here the only exception that can be thrown is when raising to a power
300  // that cannot be represented by unsigned long.
301  try {
302  T retval(str_ptr.get());
303  // NOTE: possible optimizations here include going through direct GMP routines.
304  retval *= T(1, 10).pow(digits);
305  retval *= T(10).pow(exp);
306  return retval;
307  } catch (...) {
308  piranha_throw(std::overflow_error, "error in conversion of real to rational: exponent is too large");
309  }
310  }
311  // In-place addition.
312  // NOTE: all sorts of optimisations, here and in binary add, are possible (e.g., steal from rvalue ref,
313  // avoid setting precision twice in binary operators, etc.). For the moment we keep it basic.
314  real &in_place_add(const real &r)
315  {
316  if (r.get_prec() > get_prec()) {
317  // Re-init this with the prec of r.
318  *this = real{*this, r.get_prec()};
319  }
320  ::mpfr_add(m_value, m_value, r.m_value, default_rnd);
321  return *this;
322  }
323  template <typename T, typename std::enable_if<is_mp_rational<T>::value, int>::type = 0>
324  real &in_place_add(const T &q)
325  {
326  auto v = q.get_mpq_view();
327  ::mpfr_add_q(m_value, m_value, v, default_rnd);
328  return *this;
329  }
330  template <typename T, typename std::enable_if<is_mp_integer<T>::value, int>::type = 0>
331  real &in_place_add(const T &n)
332  {
333  auto v = n.get_mpz_view();
334  ::mpfr_add_z(m_value, m_value, v, default_rnd);
335  return *this;
336  }
337  // NOTE: possible optimisations here.
338  template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
339  real &in_place_add(const T &n)
340  {
341  return in_place_add(integer(n));
342  }
343  // NOTE: possible optimisations here as well.
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)
346  {
347  // Construct real with the same precision as this, then add.
348  return in_place_add(real{x, get_prec()});
349  }
350  // Binary add.
351  static real binary_add(const real &a, const real &b)
352  {
353  real retval{a};
354  retval += b;
355  return retval;
356  }
357  // Single implementation for all interoperable types.
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)
360  {
361  real retval{a};
362  retval += b;
363  return retval;
364  }
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)
367  {
368  return binary_add(b, a);
369  }
370  // In-place subtraction.
371  real &in_place_sub(const real &r)
372  {
373  if (r.get_prec() > get_prec()) {
374  *this = real{*this, r.get_prec()};
375  }
376  ::mpfr_sub(m_value, m_value, r.m_value, default_rnd);
377  return *this;
378  }
379  template <typename T, typename std::enable_if<is_mp_rational<T>::value, int>::type = 0>
380  real &in_place_sub(const T &q)
381  {
382  auto v = q.get_mpq_view();
383  ::mpfr_sub_q(m_value, m_value, v, default_rnd);
384  return *this;
385  }
386  template <typename T, typename std::enable_if<is_mp_integer<T>::value, int>::type = 0>
387  real &in_place_sub(const T &n)
388  {
389  auto v = n.get_mpz_view();
390  ::mpfr_sub_z(m_value, m_value, v, default_rnd);
391  return *this;
392  }
393  template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
394  real &in_place_sub(const T &n)
395  {
396  return in_place_sub(integer(n));
397  }
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)
400  {
401  return in_place_sub(real{x, get_prec()});
402  }
403  // Binary sub.
404  static real binary_sub(const real &a, const real &b)
405  {
406  real retval{a};
407  retval -= b;
408  return retval;
409  }
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)
412  {
413  real retval{a};
414  retval -= b;
415  return retval;
416  }
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)
419  {
420  auto retval = binary_sub(b, a);
421  retval.negate();
422  return retval;
423  }
424  // In-place multiplication.
425  real &in_place_mul(const real &r)
426  {
427  if (r.get_prec() > get_prec()) {
428  *this = real{*this, r.get_prec()};
429  }
430  ::mpfr_mul(m_value, m_value, r.m_value, default_rnd);
431  return *this;
432  }
433  template <typename T, typename std::enable_if<is_mp_rational<T>::value, int>::type = 0>
434  real &in_place_mul(const T &q)
435  {
436  auto v = q.get_mpq_view();
437  ::mpfr_mul_q(m_value, m_value, v, default_rnd);
438  return *this;
439  }
440  template <typename T, typename std::enable_if<is_mp_integer<T>::value, int>::type = 0>
441  real &in_place_mul(const T &n)
442  {
443  auto v = n.get_mpz_view();
444  ::mpfr_mul_z(m_value, m_value, v, default_rnd);
445  return *this;
446  }
447  template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
448  real &in_place_mul(const T &n)
449  {
450  return in_place_mul(integer(n));
451  }
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)
454  {
455  return in_place_mul(real{x, get_prec()});
456  }
457  // Binary mul.
458  static real binary_mul(const real &a, const real &b)
459  {
460  real retval{a};
461  retval *= b;
462  return retval;
463  }
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)
466  {
467  real retval{a};
468  retval *= b;
469  return retval;
470  }
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)
473  {
474  return binary_mul(b, a);
475  }
476  // In-place division.
477  real &in_place_div(const real &r)
478  {
479  if (r.get_prec() > get_prec()) {
480  *this = real{*this, r.get_prec()};
481  }
482  ::mpfr_div(m_value, m_value, r.m_value, default_rnd);
483  return *this;
484  }
485  template <typename T, typename std::enable_if<is_mp_rational<T>::value, int>::type = 0>
486  real &in_place_div(const T &q)
487  {
488  auto v = q.get_mpq_view();
489  ::mpfr_div_q(m_value, m_value, v, default_rnd);
490  return *this;
491  }
492  template <typename T, typename std::enable_if<is_mp_integer<T>::value, int>::type = 0>
493  real &in_place_div(const T &n)
494  {
495  auto v = n.get_mpz_view();
496  ::mpfr_div_z(m_value, m_value, v, default_rnd);
497  return *this;
498  }
499  template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
500  real &in_place_div(const T &n)
501  {
502  return in_place_div(integer(n));
503  }
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)
506  {
507  return in_place_div(real{x, get_prec()});
508  }
509  // Binary div.
510  static real binary_div(const real &a, const real &b)
511  {
512  real retval{a};
513  retval /= b;
514  return retval;
515  }
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)
518  {
519  real retval{a};
520  retval /= b;
521  return retval;
522  }
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)
525  {
526  // Create with same precision as b.
527  real retval{a, b.get_prec()};
528  retval /= b;
529  return retval;
530  }
531  // Equality.
532  static bool binary_equality(const real &r1, const real &r2)
533  {
534  return (::mpfr_equal_p(r1.m_value, r2.m_value) != 0);
535  }
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)
538  {
539  if (r.is_nan()) {
540  return false;
541  }
542  auto v = n.get_mpz_view();
543  return (::mpfr_cmp_z(r.m_value, v) == 0);
544  }
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)
547  {
548  if (r.is_nan()) {
549  return false;
550  }
551  auto v = q.get_mpq_view();
552  return (::mpfr_cmp_q(r.m_value, v) == 0);
553  }
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)
556  {
557  if (r.is_nan()) {
558  return false;
559  }
560  return r == integer(n);
561  }
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)
564  {
565  if (r.is_nan() || std::isnan(x)) {
566  return false;
567  }
568  return r == real{x, r.get_prec()};
569  }
570  // NOTE: this is the reverse of above.
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)
573  {
574  return binary_equality(r, x);
575  }
576  // Binary less-than.
577  static bool binary_less_than(const real &r1, const real &r2)
578  {
579  return (::mpfr_less_p(r1.m_value, r2.m_value) != 0);
580  }
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)
583  {
584  auto v = q.get_mpq_view();
585  return (::mpfr_cmp_q(r.m_value, v) < 0);
586  }
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)
589  {
590  auto v = n.get_mpz_view();
591  return (::mpfr_cmp_z(r.m_value, v) < 0);
592  }
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)
595  {
596  return r < integer(n);
597  }
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)
600  {
601  return r < real{x, r.get_prec()};
602  }
603  // Binary less-than or equal.
604  static bool binary_leq(const real &r1, const real &r2)
605  {
606  return (::mpfr_lessequal_p(r1.m_value, r2.m_value) != 0);
607  }
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)
610  {
611  auto v = q.get_mpq_view();
612  return (::mpfr_cmp_q(r.m_value, v) <= 0);
613  }
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)
616  {
617  auto v = n.get_mpz_view();
618  return (::mpfr_cmp_z(r.m_value, v) <= 0);
619  }
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)
622  {
623  return r <= integer(n);
624  }
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)
627  {
628  return r <= real{x, r.get_prec()};
629  }
630  // Inverse forms of less-than and leq.
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)
633  {
634  return !binary_leq(r, x);
635  }
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)
638  {
639  return !binary_less_than(r, x);
640  }
641  // NOTE: we need to handle separately the NaNs as we cannot resort to the inversion of the comparison operators for
642  // them.
643  static bool check_nan(const real &r)
644  {
645  return r.is_nan();
646  }
647  template <typename T>
648  static bool check_nan(const T &x, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr)
649  {
650  return std::isnan(x);
651  }
652  template <typename T>
653  static bool check_nan(const T &, typename std::enable_if<!std::is_floating_point<T>::value>::type * = nullptr)
654  {
655  return false;
656  }
657  template <typename T, typename U>
658  static bool is_nan_comparison(const T &a, const U &b)
659  {
660  return (check_nan(a) || check_nan(b));
661  }
662  // Serialization support.
663  friend class boost::serialization::access;
664  // Utility function to infer the size (in number of limbs) from the precision.
665  static ::mpfr_prec_t size_from_prec(::mpfr_prec_t prec)
666  {
667  const ::mpfr_prec_t q = prec / ::mp_bits_per_limb, r = prec % ::mp_bits_per_limb;
668  return q + (r != 0);
669  }
670  // Portable s11n.
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
673  {
674  // NOTE: like in mp_integer, the performance here can be improved significantly.
675  std::ostringstream oss;
676  oss << *this;
677  auto prec = get_prec();
678  auto s = oss.str();
679  piranha::boost_save(ar, prec);
680  piranha::boost_save(ar, s);
681  }
682  template <class Archive, enable_if_t<!std::is_same<Archive, boost::archive::binary_iarchive>::value, int> = 0>
683  void load(Archive &ar, unsigned)
684  {
685  ::mpfr_prec_t prec;
686  PIRANHA_MAYBE_TLS std::string s;
687  piranha::boost_load(ar, prec);
688  piranha::boost_load(ar, s);
689  *this = real(s, prec);
690  }
691  // Binary s11n.
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
694  {
695  piranha::boost_save(ar, m_value->_mpfr_prec);
696  piranha::boost_save(ar, m_value->_mpfr_sign);
697  piranha::boost_save(ar, m_value->_mpfr_exp);
698  const ::mpfr_prec_t s = size_from_prec(m_value->_mpfr_prec);
699  // NOTE: no need to save the size, as it can be recovered from the prec.
700  for (::mpfr_prec_t i = 0; i < s; ++i) {
701  piranha::boost_save(ar, m_value->_mpfr_d[i]);
702  }
703  }
704  template <class Archive, enable_if_t<std::is_same<Archive, boost::archive::binary_iarchive>::value, int> = 0>
705  void load(Archive &ar, unsigned)
706  {
707  // First we recover the non-limb members.
708  ::mpfr_prec_t prec;
709  decltype(m_value->_mpfr_sign) sign;
710  decltype(m_value->_mpfr_exp) exp;
711  piranha::boost_load(ar, prec);
714  // Recover the size in limbs from prec.
715  const ::mpfr_prec_t s = size_from_prec(prec);
716  // Set the precision.
717  set_prec(prec);
718  piranha_assert(m_value->_mpfr_prec == prec);
719  m_value->_mpfr_sign = sign;
720  m_value->_mpfr_exp = exp;
721  try {
722  // NOTE: protect in try/catch as in theory boost_load() could throw even
723  // in case of valid archive (e.g., memory errors maybe?) and we want
724  // to deal with this case.
725  for (::mpfr_prec_t i = 0; i < s; ++i) {
726  piranha::boost_load(ar, *(m_value->_mpfr_d + i));
727  }
728  } catch (...) {
729  // Set to zero before re-throwing.
730  ::mpfr_set_ui(m_value, 0u, default_rnd);
731  throw;
732  }
733  }
734  BOOST_SERIALIZATION_SPLIT_MEMBER()
735 public:
737 
741  {
742  ::mpfr_init2(m_value, default_prec);
743  ::mpfr_set_zero(m_value, 0);
744  }
746 
751  real(const real &other)
752  {
753  // Init with the same precision as other, and then set.
754  ::mpfr_init2(m_value, other.get_prec());
755  ::mpfr_set(m_value, other.m_value, default_rnd);
756  }
758 
761  real(real &&other) noexcept
762  {
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;
767  // Erase other.
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;
772  }
774 
784  explicit real(const char *str, const ::mpfr_prec_t &prec = default_prec)
785  {
786  construct_from_string(str, prec);
787  }
789 
797  explicit real(const std::string &str, const ::mpfr_prec_t &prec = default_prec)
798  {
799  construct_from_string(str.c_str(), prec);
800  }
802 
811  explicit real(const real &other, const ::mpfr_prec_t &prec)
812  {
813  prec_check(prec);
814  ::mpfr_init2(m_value, prec);
815  ::mpfr_set(m_value, other.m_value, default_rnd);
816  }
818 
828  template <typename T, typename = generic_ctor_enabler<T>>
829  explicit real(const T &x, const ::mpfr_prec_t &prec = default_prec)
830  {
831  prec_check(prec);
832  ::mpfr_init2(m_value, prec);
833  construct_from_generic(x);
834  }
836 
839  ~real();
841 
848  real &operator=(const real &other)
849  {
850  if (this != &other) {
851  // Handle assignment to moved-from objects.
852  if (m_value->_mpfr_d) {
853  // Copy the precision. This will also reset the internal value.
854  set_prec(other.get_prec());
855  } else {
856  piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
857  // Reinit before setting.
858  ::mpfr_init2(m_value, other.get_prec());
859  }
860  ::mpfr_set(m_value, other.m_value, default_rnd);
861  }
862  return *this;
863  }
865 
870  real &operator=(real &&other) noexcept
871  {
872  // NOTE: swap() already has the check for this.
873  swap(other);
874  return *this;
875  }
877 
886  real &operator=(const std::string &str)
887  {
888  return operator=(str.c_str());
889  }
891 
905  real &operator=(const char *str)
906  {
907  // Handle moved-from objects.
908  if (m_value->_mpfr_d) {
909  assign_from_string(str);
910  } else {
911  piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
912  construct_from_string(str, default_prec);
913  }
914  return *this;
915  }
917 
930  template <typename T, typename = generic_ctor_enabler<T>>
931  real &operator=(const T &x)
932  {
933  if (!m_value->_mpfr_d) {
934  piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
935  // Re-init with default prec if it was moved-from.
936  ::mpfr_init2(m_value, default_prec);
937  }
938  // NOTE: all construct_from_generic() methods here are really assignments.
939  construct_from_generic(x);
940  return *this;
941  }
943 
965  template <typename T, typename = cast_enabler<T>>
966  explicit operator T() const
967  {
968  return convert_to_impl<T>();
969  }
971 
976  void swap(real &other)
977  {
978  if (this == &other) {
979  return;
980  }
981  ::mpfr_swap(m_value, other.m_value);
982  }
984 
988  int sign() const
989  {
990  if (is_nan()) {
991  return 0;
992  } else {
993  return mpfr_sgn(m_value);
994  }
995  }
997 
1000  bool is_zero() const
1001  {
1002  return (mpfr_zero_p(m_value) != 0);
1003  }
1005 
1008  bool is_nan() const
1009  {
1010  return mpfr_nan_p(m_value) != 0;
1011  }
1013 
1016  bool is_inf() const
1017  {
1018  return mpfr_inf_p(m_value) != 0;
1019  }
1021 
1024  ::mpfr_prec_t get_prec() const
1025  {
1026  return mpfr_get_prec(m_value);
1027  }
1029 
1037  void set_prec(const ::mpfr_prec_t &prec)
1038  {
1039  prec_check(prec);
1040  ::mpfr_set_prec(m_value, prec);
1041  }
1043 
1046  void negate()
1047  {
1048  ::mpfr_neg(m_value, m_value, default_rnd);
1049  }
1051 
1055  void truncate()
1056  {
1057  if (is_inf() || is_nan()) {
1058  return;
1059  }
1060  ::mpfr_trunc(m_value, m_value);
1061  }
1063 
1066  real truncated() const
1067  {
1068  real retval{*this};
1069  retval.truncate();
1070  return retval;
1071  }
1073 
1088  template <typename T>
1089  auto operator+=(const T &x) -> decltype(this->in_place_add(x))
1090  {
1091  return in_place_add(x);
1092  }
1094 
1109  template <typename T, generic_in_place_enabler<T> = 0>
1110  friend T &operator+=(T &x, const real &r)
1111  {
1112  // NOTE: for the supported types, move assignment can never throw.
1113  return x = static_cast<T>(r + x);
1114  }
1116 
1132  template <typename T, typename U>
1133  friend auto operator+(const T &x, const U &y) -> decltype(real::binary_add(x, y))
1134  {
1135  return binary_add(x, y);
1136  }
1138 
1141  real operator+() const
1142  {
1143  return *this;
1144  }
1146 
1152  {
1153  return operator+=(1);
1154  }
1156 
1162  {
1163  const real retval(*this);
1164  ++(*this);
1165  return retval;
1166  }
1168 
1183  template <typename T>
1184  auto operator-=(const T &x) -> decltype(this->in_place_sub(x))
1185  {
1186  return in_place_sub(x);
1187  }
1189 
1204  template <typename T, generic_in_place_enabler<T> = 0>
1205  friend T &operator-=(T &x, const real &r)
1206  {
1207  return x = static_cast<T>(x - r);
1208  }
1210 
1226  template <typename T, typename U>
1227  friend auto operator-(const T &x, const U &y) -> decltype(real::binary_sub(x, y))
1228  {
1229  return binary_sub(x, y);
1230  }
1232 
1235  real operator-() const
1236  {
1237  real retval(*this);
1238  retval.negate();
1239  return retval;
1240  }
1242 
1248  {
1249  return operator-=(1);
1250  }
1252 
1258  {
1259  const real retval(*this);
1260  --(*this);
1261  return retval;
1262  }
1264 
1279  template <typename T>
1280  auto operator*=(const T &x) -> decltype(this->in_place_mul(x))
1281  {
1282  return in_place_mul(x);
1283  }
1285 
1300  template <typename T, generic_in_place_enabler<T> = 0>
1301  friend T &operator*=(T &x, const real &r)
1302  {
1303  return x = static_cast<T>(x * r);
1304  }
1306 
1322  template <typename T, typename U>
1323  friend auto operator*(const T &x, const U &y) -> decltype(real::binary_mul(x, y))
1324  {
1325  return binary_mul(x, y);
1326  }
1328 
1343  template <typename T>
1344  auto operator/=(const T &x) -> decltype(this->in_place_div(x))
1345  {
1346  return in_place_div(x);
1347  }
1349 
1364  template <typename T, generic_in_place_enabler<T> = 0>
1365  friend T &operator/=(T &x, const real &r)
1366  {
1367  return x = static_cast<T>(x / r);
1368  }
1370 
1386  template <typename T, typename U>
1387  friend auto operator/(const T &x, const U &y) -> decltype(real::binary_div(x, y))
1388  {
1389  return binary_div(x, y);
1390  }
1392 
1402  real &multiply_accumulate(const real &r1, const real &r2)
1403  {
1404  const ::mpfr_prec_t prec1 = std::max<::mpfr_prec_t>(r1.get_prec(), r2.get_prec());
1405  if (prec1 > get_prec()) {
1406  *this = real{*this, prec1};
1407  }
1408 // So the story here is that mpfr_fma has been reported to be slower than the two separate
1409 // operations. Benchmarks on fateman1 indicate this is indeed the case (3.6 vs 2.7 secs
1410 // on 4 threads). Hopefully it will be fixed in the future, for now adopt the workaround.
1411 // http://www.loria.fr/~zimmerma/mpfr-mpc-2014.html
1412 // NOTE: this optimisation requires the thread_local keyword.
1413 #if defined(PIRANHA_HAVE_THREAD_LOCAL)
1414  static thread_local real tmp;
1415  // NOTE: set the same precision as this, which is now the max precision of the 3 operands.
1416  // If we do not do this, then tmp has an undeterminate precision. Use the raw MPFR function
1417  // in order to avoid the checks in get_prec(), as we know the precision has a sane value.
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);
1421 #else
1422  ::mpfr_fma(m_value, r1.m_value, r2.m_value, m_value, default_rnd);
1423 #endif
1424  return *this;
1425  }
1427 
1442  template <typename T, typename U>
1443  friend auto operator==(const T &x, const U &y) -> decltype(real::binary_equality(x, y))
1444  {
1445  return binary_equality(x, y);
1446  }
1448 
1463  template <typename T, typename U>
1464  friend auto operator!=(const T &x, const U &y) -> decltype(!real::binary_equality(x, y))
1465  {
1466  return !binary_equality(x, y);
1467  }
1469 
1484  template <typename T, typename U>
1485  friend auto operator<(const T &x, const U &y) -> decltype(real::binary_less_than(x, y))
1486  {
1487  if (is_nan_comparison(x, y)) {
1488  return false;
1489  }
1490  return binary_less_than(x, y);
1491  }
1493 
1508  template <typename T, typename U>
1509  friend auto operator<=(const T &x, const U &y) -> decltype(real::binary_leq(x, y))
1510  {
1511  if (is_nan_comparison(x, y)) {
1512  return false;
1513  }
1514  return binary_leq(x, y);
1515  }
1517 
1532  template <typename T, typename U>
1533  friend auto operator>(const T &x, const U &y) -> decltype(real::binary_less_than(y, x))
1534  {
1535  if (is_nan_comparison(x, y)) {
1536  return false;
1537  }
1538  return y < x;
1539  }
1541 
1556  template <typename T, typename U>
1557  friend auto operator>=(const T &x, const U &y) -> decltype(real::binary_leq(y, x))
1558  {
1559  if (is_nan_comparison(x, y)) {
1560  return false;
1561  }
1562  return y <= x;
1563  }
1565 
1572  real pow(const real &exp) const
1573  {
1574  real retval{0, get_prec()};
1575  if (exp.get_prec() > get_prec()) {
1576  retval.set_prec(exp.get_prec());
1577  }
1578  ::mpfr_pow(retval.m_value, m_value, exp.m_value, default_rnd);
1579  return retval;
1580  }
1582 
1585  real gamma() const
1586  {
1587  real retval{0, get_prec()};
1588  ::mpfr_gamma(retval.m_value, m_value, default_rnd);
1589  return retval;
1590  }
1592 
1595  real lgamma() const
1596  {
1597  real retval{0, get_prec()};
1598  // This is the sign of gamma(*this). We don't use this.
1599  int sign;
1600  ::mpfr_lgamma(retval.m_value, &sign, m_value, default_rnd);
1601  return retval;
1602  }
1604 
1607  real exp() const
1608  {
1609  real retval{0, get_prec()};
1610  ::mpfr_exp(retval.m_value, m_value, default_rnd);
1611  return retval;
1612  }
1613  real binomial(const real &) const;
1615 
1618  real abs() const
1619  {
1620  real retval(*this);
1621  ::mpfr_abs(retval.m_value, retval.m_value, default_rnd);
1622  return retval;
1623  }
1625 
1628  real sin() const
1629  {
1630  real retval(0, get_prec());
1631  ::mpfr_sin(retval.m_value, m_value, default_rnd);
1632  return retval;
1633  }
1635 
1638  real cos() const
1639  {
1640  real retval(0, get_prec());
1641  ::mpfr_cos(retval.m_value, m_value, default_rnd);
1642  return retval;
1643  }
1645 
1648  real pi() const
1649  {
1650  real retval(0, get_prec());
1651  ::mpfr_const_pi(retval.m_value, default_rnd);
1652  return retval;
1653  }
1655 
1671  friend std::ostream &operator<<(std::ostream &os, const real &r)
1672  {
1673  if (r.is_nan()) {
1674  os << "nan";
1675  return os;
1676  }
1677  if (r.is_inf()) {
1678  if (r.sign() > 0) {
1679  os << "inf";
1680  } else {
1681  os << "-inf";
1682  }
1683  return os;
1684  }
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)) {
1688  piranha_throw(std::overflow_error,
1689  "error in conversion of real to rational: the call to the MPFR function failed");
1690  }
1691  smart_mpfr_str str(cptr, ::mpfr_free_str);
1692  // Copy into C++ string.
1693  std::string cpp_str(str.get());
1694  // Insert the radix point.
1695  auto it = std::find_if(cpp_str.begin(), cpp_str.end(), is_digit);
1696  if (it != cpp_str.end()) {
1697  ++it;
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");
1701  }
1702  --exp;
1703  if (exp != ::mpfr_exp_t(0) && r.sign() != 0) {
1704  cpp_str.append("e" + boost::lexical_cast<std::string>(exp));
1705  }
1706  }
1707  os << cpp_str;
1708  return os;
1709  }
1711 
1721  friend std::istream &operator>>(std::istream &is, real &r)
1722  {
1723  std::string tmp_str;
1724  std::getline(is, tmp_str);
1725  r = tmp_str;
1726  return is;
1727  }
1733  std::remove_extent<::mpfr_t>::type *get_mpfr_t()
1735  {
1736  return &m_value[0u];
1737  }
1739  const std::remove_extent<::mpfr_t>::type *get_mpfr_t() const
1740  {
1741  return &m_value[0u];
1742  }
1744 
1745 #if defined(PIRANHA_WITH_MSGPACK)
1746 private:
1747  // msgpack enabler.
1748  template <typename Stream>
1749  using msgpack_pack_enabler
1750  = enable_if_t<conjunction<is_msgpack_stream<Stream>, has_msgpack_pack<Stream, ::mpfr_prec_t>,
1755  has_safe_cast<std::uint32_t, ::mpfr_prec_t>>::value,
1756  int>;
1757  template <typename U>
1758  using msgpack_convert_enabler
1759  = enable_if_t<conjunction<std::is_same<U, U>, // For SFINAE.
1764  int>;
1765 
1766 public:
1768 
1789  template <typename Stream, msgpack_pack_enabler<Stream> = 0>
1790  void msgpack_pack(msgpack::packer<Stream> &p, msgpack_format f) const
1791  {
1792  if (f == msgpack_format::portable) {
1793  std::ostringstream oss;
1794  oss << *this;
1795  auto prec = get_prec();
1796  auto s = oss.str();
1797  p.pack_array(2);
1798  piranha::msgpack_pack(p, prec, f);
1799  piranha::msgpack_pack(p, s, f);
1800  } else {
1801  // NOTE: storing both prec and the number of limbs is a bit redundant: it is possible to
1802  // infer the number of limbs from prec but not viceversa (only an upper/lower bound). So let's
1803  // store them both.
1804  p.pack_array(4);
1805  piranha::msgpack_pack(p, m_value->_mpfr_prec, f);
1806  piranha::msgpack_pack(p, m_value->_mpfr_sign, f);
1807  piranha::msgpack_pack(p, m_value->_mpfr_exp, f);
1808  const auto s = safe_cast<std::uint32_t>(size_from_prec(m_value->_mpfr_prec));
1809  p.pack_array(s);
1810  // NOTE: no need to save the size, as it can be recovered from the prec.
1811  for (std::uint32_t i = 0; i < s; ++i) {
1812  piranha::msgpack_pack(p, m_value->_mpfr_d[i], f);
1813  }
1814  }
1815  }
1817 
1840  template <typename U = real, msgpack_convert_enabler<U> = 0>
1841  void msgpack_convert(const msgpack::object &o, msgpack_format f)
1842  {
1843  if (f == msgpack_format::portable) {
1844  PIRANHA_MAYBE_TLS std::array<msgpack::object, 2> vobj;
1845  o.convert(vobj);
1846  ::mpfr_prec_t prec;
1847  PIRANHA_MAYBE_TLS std::string s;
1848  piranha::msgpack_convert(prec, vobj[0], f);
1849  piranha::msgpack_convert(s, vobj[1], f);
1850  *this = real(s, prec);
1851  } else {
1852  PIRANHA_MAYBE_TLS std::array<msgpack::object, 4> vobj;
1853  o.convert(vobj);
1854  // First let's handle the non-limbs members.
1855  ::mpfr_prec_t prec;
1856  decltype(m_value->_mpfr_sign) sign;
1857  decltype(m_value->_mpfr_exp) exp;
1858  piranha::msgpack_convert(prec, vobj[0], f);
1859  piranha::msgpack_convert(sign, vobj[1], f);
1860  piranha::msgpack_convert(exp, vobj[2], f);
1861  set_prec(prec);
1862  piranha_assert(m_value->_mpfr_prec == prec);
1863  m_value->_mpfr_sign = sign;
1864  m_value->_mpfr_exp = exp;
1865  // Next the limbs. Protect in try/catch so if anything goes wrong we can fix this in the
1866  // catch block before re-throwing.
1867  try {
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())) {
1872  piranha_throw(std::invalid_argument,
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) + ")");
1878  }
1879  for (decltype(vlimbs.size()) i = 0; i < s; ++i) {
1880  piranha::msgpack_convert(m_value->_mpfr_d[i], vlimbs[i], f);
1881  }
1882  } catch (...) {
1883  // Set to zero before re-throwing.
1884  ::mpfr_set_ui(m_value, 0u, default_rnd);
1885  throw;
1886  }
1887  }
1888  }
1889 #endif
1890 
1891 private:
1892  ::mpfr_t m_value;
1893 };
1894 
1895 namespace math
1896 {
1897 
1899 template <typename T>
1900 struct negate_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
1902 
1905  void operator()(real &x) const
1906  {
1907  x.negate();
1908  }
1909 };
1910 
1912 template <typename T>
1913 struct is_zero_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
1915 
1920  bool operator()(const T &r) const
1921  {
1922  return r.is_zero();
1923  }
1924 };
1925 }
1926 
1927 namespace detail
1928 {
1929 
1930 // Enabler for real pow.
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;
1936 
1937 // Binomial follows the same rules as pow.
1938 template <typename T, typename U>
1939 using real_binomial_enabler = real_pow_enabler<T, U>;
1940 }
1941 
1942 namespace math
1943 {
1944 
1946 
1955 template <typename T, typename U>
1956 struct pow_impl<T, U, detail::real_pow_enabler<T, U>> {
1958 
1966  real operator()(const real &r, const real &x) const
1967  {
1968  return r.pow(x);
1969  }
1971 
1980  template <typename T2>
1981  real operator()(const real &r, const T2 &x) const
1982  {
1983  // NOTE: init with the same precision as r in order
1984  // to maintain the same precision in the result.
1985  return r.pow(real{x, r.get_prec()});
1986  }
1988 
1997  template <typename T2>
1998  real operator()(const T2 &r, const real &x) const
1999  {
2000  return real{r, x.get_prec()}.pow(x);
2001  }
2002 };
2003 
2005 template <typename T>
2006 struct sin_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2008 
2015  real operator()(const T &r) const
2016  {
2017  return r.sin();
2018  }
2019 };
2020 
2022 template <typename T>
2023 struct cos_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2025 
2032  real operator()(const T &r) const
2033  {
2034  return r.cos();
2035  }
2036 };
2037 
2039 template <typename T>
2040 struct abs_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2042 
2047  T operator()(const T &x) const
2048  {
2049  return x.abs();
2050  }
2051 };
2052 
2054 template <typename T>
2055 struct partial_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2057 
2060  real operator()(const real &, const std::string &) const
2061  {
2062  return real(0);
2063  }
2064 };
2065 
2067 
2076 template <typename T, typename U>
2077 struct binomial_impl<T, U, detail::real_binomial_enabler<T, U>> {
2079 
2087  real operator()(const real &x, const real &y) const
2088  {
2089  return x.binomial(y);
2090  }
2092 
2101  template <typename T2>
2102  real operator()(const real &x, const T2 &y) const
2103  {
2104  // NOTE: init with the same precision as r in order
2105  // to maintain the same precision in the result.
2106  return x.binomial(real{y, x.get_prec()});
2107  }
2109 
2118  template <typename T2>
2119  real operator()(const T2 &x, const real &y) const
2120  {
2121  return real{x, y.get_prec()}.binomial(y);
2122  }
2123 };
2124 
2126 template <>
2129 
2136  void operator()(real &x, const real &y, const real &z) const
2137  {
2138  x.multiply_accumulate(y, z);
2139  }
2140 };
2141 }
2142 
2143 inline real::~real()
2144 {
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);
2150  } else {
2151 // NOTE: the story here is that ICC has a weird behaviour when the thread_local
2152 // storage. Essentially, the thread-local static variable in the fma() function
2153 // upon destruction has the _mpfr_d set to zero for some reason but the other members
2154 // are not zeroed out. This results in the asserts below firing, and probably a memory
2155 // leak as well as the variable is not cleared. We just disable the asserts for now.
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);
2160 #endif
2161  }
2162 }
2163 
2164 namespace detail
2165 {
2166 
2167 // Compute gamma(a)/(gamma(b) * gamma(c)), assuming a, b and c are not negative ints. The logarithm
2168 // of the gamma function is used internally.
2169 inline real real_compute_3_gamma(const real &a, const real &b, const real &c, const ::mpfr_prec_t &prec)
2170 {
2171  // Here we should never enter with negative ints.
2172  piranha_assert(a.sign() >= 0 || a.truncated() != a);
2173  piranha_assert(b.sign() >= 0 || b.truncated() != b);
2174  piranha_assert(c.sign() >= 0 || c.truncated() != c);
2175  const real pi = real{0, prec}.pi();
2176  real tmp0(0), tmp1(1);
2177  if (a.sign() < 0) {
2178  tmp0 -= (1 - a).lgamma();
2179  tmp1 *= pi / (a * pi).sin();
2180  } else {
2181  tmp0 += a.lgamma();
2182  }
2183  if (b.sign() < 0) {
2184  tmp0 += (1 - b).lgamma();
2185  tmp1 *= (b * pi).sin() / pi;
2186  } else {
2187  tmp0 -= b.lgamma();
2188  }
2189  if (c.sign() < 0) {
2190  tmp0 += (1 - c).lgamma();
2191  tmp1 *= (c * pi).sin() / pi;
2192  } else {
2193  tmp0 -= c.lgamma();
2194  }
2195  return tmp0.exp() * tmp1;
2196 }
2197 }
2198 
2200 
2214 inline real real::binomial(const real &y) const
2215 {
2216  if (unlikely(is_nan() || is_inf() || y.is_nan() || y.is_inf())) {
2217  piranha_throw(std::invalid_argument, "cannot compute binomial coefficient with non-finite real argument(s)");
2218  }
2219  // Work with the max precision.
2220  const ::mpfr_prec_t max_prec = std::max<::mpfr_prec_t>(get_prec(), y.get_prec());
2221  const bool neg_int_x = truncated() == (*this) && sign() < 0, neg_int_y = y.truncated() == y && y.sign() < 0,
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);
2224  switch (mask) {
2225  case 0u:
2226  // Case 0 is the non-special one, use the default implementation.
2227  return detail::real_compute_3_gamma((*this) + 1, y + 1, (*this) - y + 1, max_prec);
2228  // NOTE: case 1 is not possible: x < 0, y > 0 implies x - y < 0 always.
2229  case 2u:
2230  case 4u:
2231  // These are finite numerators with infinite denominators.
2232  return real{0, max_prec};
2233  // NOTE: case 6 is not possible: x > 0, y < 0 implies x - y > 0 always.
2234  case 3u: {
2235  // 3 and 5 are the cases with 1 inf in num and 1 inf in den. Use the transformation
2236  // formula to make them finite.
2237  // NOTE: the phase here is really just a sign, but it seems tricky to compute this exactly
2238  // due to potential rounding errors. We are attempting to err on the safe side by using pow()
2239  // here.
2240  const auto phase = math::pow(-1, (*this) + 1) / math::pow(-1, y + 1);
2241  return detail::real_compute_3_gamma(-y, -(*this), (*this) - y + 1, max_prec) * phase;
2242  }
2243  case 5u: {
2244  const auto phase = math::pow(-1, (*this) - y + 1) / math::pow(-1, (*this) + 1);
2245  return detail::real_compute_3_gamma(-((*this) - y), y + 1, -(*this), max_prec) * phase;
2246  }
2247  }
2248  // Case 7 returns zero -> from inf / (inf * inf) it becomes a / (b * inf) after the transform.
2249  // NOTE: put it here so the compiler does not complain about missing return statement in the switch block.
2250  return real{0, max_prec};
2251 }
2252 
2253 inline namespace impl
2254 {
2255 
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>;
2260 }
2261 
2263 
2268 template <typename To, typename From>
2269 struct safe_cast_impl<To, From, sc_real_enabler<To, From>> {
2270 private:
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>;
2275 
2276 public:
2278 
2292  template <typename T = To, integral_enabler<T> = 0>
2293  T operator()(const real &r) const
2294  {
2295  // NOTE: the finiteness check here is repeated in the cast below, but we need it here in order
2296  // to make sure that we can compute the truncated r.
2297  if (unlikely(r.is_inf() || r.is_nan() || r.truncated() != r)) {
2298  piranha_throw(safe_cast_failure, "cannot convert the input real " + boost::lexical_cast<std::string>(r)
2299  + " to the integral type '" + detail::demangle<To>()
2300  + "', as the input real does not represent a finite integral value");
2301  }
2302  try {
2303  return static_cast<T>(r);
2304  } catch (const std::overflow_error &) {
2305  piranha_throw(safe_cast_failure, "cannot convert the input real " + boost::lexical_cast<std::string>(r)
2306  + " to the integral type '" + detail::demangle<To>()
2307  + "', as the conversion would not preserve the value");
2308  }
2309  }
2311 
2322  template <typename T = To, rational_enabler<T> = 0>
2323  T operator()(const real &r) const
2324  {
2325  try {
2326  return static_cast<T>(r);
2327  } catch (const std::overflow_error &) {
2328  piranha_throw(safe_cast_failure, "cannot convert the input real " + boost::lexical_cast<std::string>(r)
2329  + " to the rational type '" + detail::demangle<To>()
2330  + "', as the conversion would not preserve the value");
2331  }
2332  }
2333 };
2334 
2335 inline namespace literals
2336 {
2337 
2339 
2349 inline real operator"" _r(const char *s)
2350 {
2351  return real(s);
2352 }
2353 }
2354 
2355 inline namespace impl
2356 {
2357 
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>;
2364 
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>;
2371 }
2372 
2374 
2385 template <typename Archive>
2386 struct boost_save_impl<Archive, real, real_boost_save_enabler<Archive>> : boost_save_via_boost_api<Archive, real> {
2387 };
2388 
2390 
2401 template <typename Archive>
2402 struct boost_load_impl<Archive, real, real_boost_load_enabler<Archive>> : boost_load_via_boost_api<Archive, real> {
2403 };
2404 
2405 #if defined(PIRANHA_WITH_MSGPACK)
2406 
2407 inline namespace impl
2408 {
2409 
2410 // Enablers for msgpack serialization.
2411 template <typename Stream>
2412 using real_msgpack_pack_enabler = enable_if_t<is_detected<msgpack_pack_member_t, Stream, real>::value>;
2413 
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>;
2417 }
2418 
2420 
2425 template <typename Stream>
2426 struct msgpack_pack_impl<Stream, real, real_msgpack_pack_enabler<Stream>> {
2428 
2437  void operator()(msgpack::packer<Stream> &p, const real &x, msgpack_format f) const
2438  {
2439  x.msgpack_pack(p, f);
2440  }
2441 };
2442 
2444 
2449 template <typename T>
2450 struct msgpack_convert_impl<T, real_msgpack_convert_enabler<T>> {
2452 
2461  void operator()(T &x, const msgpack::object &o, msgpack_format f) const
2462  {
2463  x.msgpack_convert(o, f);
2464  }
2465 };
2466 
2467 #endif
2468 
2469 inline namespace impl
2470 {
2471 
2472 template <typename T>
2473 using real_zero_is_absorbing_enabler = enable_if_t<std::is_same<uncvref_t<T>, real>::value>;
2474 }
2475 
2477 
2483 template <typename T>
2484 struct zero_is_absorbing<T, real_zero_is_absorbing_enabler<T>> {
2486  static const bool value = false;
2487 };
2488 
2489 template <typename T>
2491 }
2492 
2493 #endif
math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation.
Definition: pow.hpp:126
int sign() const
Sign.
Definition: real.hpp:988
real operator()(const T2 &x, const real &y) const
Call operator, real bottom overload.
Definition: real.hpp:2119
void swap(real &other)
Swap.
Definition: real.hpp:976
friend std::ostream & operator<<(std::ostream &os, const real &r)
Overload output stream operator for piranha::real.
Definition: real.hpp:1671
void msgpack_pack(msgpack::packer< Stream > &p, msgpack_format f) const
Pack in msgpack format.
Definition: real.hpp:1790
void boost_load(Archive &ar, T &x)
Load from Boost archive.
Definition: s11n.hpp:469
Default functor for the implementation of piranha::math::negate().
Definition: math.hpp:253
Multiprecision integer class.
Definition: mp++.hpp:869
friend auto operator<=(const T &x, const U &y) -> decltype(real::binary_leq(x, y))
Generic less-than or equal operator involving piranha::real.
Definition: real.hpp:1509
void operator()(msgpack::packer< Stream > &p, const real &x, msgpack_format f) const
Call operator.
Definition: real.hpp:2437
Default implementation of piranha::boost_load().
Definition: s11n.hpp:391
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
Definition: mp_integer.hpp:63
real lgamma() const
Logarithm of the gamma function.
Definition: real.hpp:1595
void msgpack_convert(T &x, const msgpack::object &o, msgpack_format f)
Convert msgpack object.
Definition: s11n.hpp:957
Default functor for the implementation of piranha::math::multiply_accumulate().
Definition: math.hpp:339
bool is_nan() const
Test for NaN.
Definition: real.hpp:1008
void truncate()
Truncate in-place.
Definition: real.hpp:1055
real & operator=(const std::string &str)
Assignment operator from C++ string.
Definition: real.hpp:886
Type trait to detect coefficient types.
Definition: is_cf.hpp:55
friend auto operator!=(const T &x, const U &y) -> decltype(!real::binary_equality(x, y))
Generic inequality operator involving piranha::real.
Definition: real.hpp:1464
real pow(const real &exp) const
Exponentiation.
Definition: real.hpp:1572
void operator()(T &x, const msgpack::object &o, msgpack_format f) const
Call operator.
Definition: real.hpp:2461
Default functor for the implementation of piranha::math::binomial().
Definition: binomial.hpp:140
real & operator=(const char *str)
Assignment operator from C string.
Definition: real.hpp:905
Default functor for the implementation of piranha::math::is_zero().
Definition: math.hpp:69
Implementation of piranha::boost_load() via the Boost API.
Definition: s11n.hpp:363
real cos() const
Cosine.
Definition: real.hpp:1638
friend auto operator-(const T &x, const U &y) -> decltype(real::binary_sub(x, y))
Generic binary subtraction involving piranha::real.
Definition: real.hpp:1227
Exceptions.
Default functor for the implementation of piranha::math::sin().
Definition: math.hpp:541
real(const T &x, const ::mpfr_prec_t &prec=default_prec)
Generic constructor.
Definition: real.hpp:829
Default implementation of piranha::boost_save().
Definition: s11n.hpp:245
STL namespace.
Default functor for the implementation of piranha::math::cos().
Definition: math.hpp:449
Arbitrary precision floating-point class.
Definition: real.hpp:126
real(const real &other, const ::mpfr_prec_t &prec)
Copy constructor with different precision.
Definition: real.hpp:811
Default functor for the implementation of piranha::math::pow().
Definition: pow.hpp:52
friend auto operator>(const T &x, const U &y) -> decltype(real::binary_less_than(y, x))
Generic greater-than operator involving piranha::real.
Definition: real.hpp:1533
real(const char *str, const ::mpfr_prec_t &prec=default_prec)
Constructor from C string.
Definition: real.hpp:784
auto operator-=(const T &x) -> decltype(this->in_place_sub(x))
In-place subtraction.
Definition: real.hpp:1184
real operator()(const real &x, const real &y) const
Call operator, real–real overload.
Definition: real.hpp:2087
real operator()(const real &r, const T2 &x) const
Call operator, real base overload.
Definition: real.hpp:1981
Detect the presence of piranha::msgpack_convert().
Definition: s11n.hpp:610
real sin() const
Sine.
Definition: real.hpp:1628
auto operator+=(const T &x) -> decltype(this->in_place_add(x))
In-place addition.
Definition: real.hpp:1089
friend auto operator>=(const T &x, const U &y) -> decltype(real::binary_leq(y, x))
Generic greater-than or equal operator involving piranha::real.
Definition: real.hpp:1557
real operator()(const real &x, const T2 &y) const
Call operator, real top overload.
Definition: real.hpp:2102
friend auto operator<(const T &x, const U &y) -> decltype(real::binary_less_than(x, y))
Generic less-than operator involving piranha::real.
Definition: real.hpp:1485
real operator()(const real &r, const real &x) const
Call operator, real–real overload.
Definition: real.hpp:1966
void negate()
Negate in-place.
Definition: real.hpp:1046
Default functor for the implementation of piranha::msgpack_convert().
Definition: s11n.hpp:867
real & operator=(const real &other)
Copy assignment operator.
Definition: real.hpp:848
real & operator++()
Prefix increment.
Definition: real.hpp:1151
~real()
Destructor.
Definition: real.hpp:2143
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
bool is_inf() const
Test for infinity.
Definition: real.hpp:1016
Default functor for the implementation of piranha::msgpack_pack().
Definition: s11n.hpp:686
real(const real &other)
Copy constructor.
Definition: real.hpp:751
msgpack_format
Serialization format for msgpack.
Definition: s11n.hpp:673
Detect if zero is a multiplicative absorber.
Default functor for the implementation of piranha::math::partial().
Definition: math.hpp:633
real truncated() const
Truncated copy.
Definition: real.hpp:1066
Default implementation of piranha::safe_cast().
Definition: safe_cast.hpp:63
real & multiply_accumulate(const real &r1, const real &r2)
Combined multiply-add.
Definition: real.hpp:1402
Default functor for the implementation of piranha::convert_to().
Definition: convert_to.hpp:43
friend auto operator*(const T &x, const U &y) -> decltype(real::binary_mul(x, y))
Generic binary multiplication involving piranha::real.
Definition: real.hpp:1323
real operator()(const real &, const std::string &) const
Call operator.
Definition: real.hpp:2060
real pi() const
Pi constant.
Definition: real.hpp:1648
Implementation of piranha::boost_save() via the Boost API.
Definition: s11n.hpp:217
void set_prec(const ::mpfr_prec_t &prec)
Set precision.
Definition: real.hpp:1037
auto operator*=(const T &x) -> decltype(this->in_place_mul(x))
In-place multiplication.
Definition: real.hpp:1280
real(const std::string &str, const ::mpfr_prec_t &prec=default_prec)
Constructor from C++ string.
Definition: real.hpp:797
friend T & operator+=(T &x, const real &r)
Generic in-place addition with piranha::real.
Definition: real.hpp:1110
real exp() const
Exponential.
Definition: real.hpp:1607
friend T & operator-=(T &x, const real &r)
Generic in-place subtraction with piranha::real.
Definition: real.hpp:1205
Root piranha namespace.
Definition: array_key.hpp:52
void msgpack_pack(msgpack::packer< Stream > &packer, const T &x, msgpack_format f)
Pack generic object in a msgpack stream.
Definition: s11n.hpp:856
real & operator=(real &&other) noexcept
Move assignment operator.
Definition: real.hpp:870
::mpfr_prec_t get_prec() const
Get precision.
Definition: real.hpp:1024
real operator--(int)
Suffix decrement.
Definition: real.hpp:1257
Detect the presence of piranha::msgpack_pack().
Definition: s11n.hpp:607
Type traits.
const std::remove_extent<::mpfr_t >::type * get_mpfr_t() const
Get a const reference to the internal mpfr_t instance.
Definition: real.hpp:1739
friend T & operator*=(T &x, const real &r)
Generic in-place multiplication by piranha::real.
Definition: real.hpp:1301
real(real &&other) noexcept
Move constructor.
Definition: real.hpp:761
real operator-() const
Negated copy.
Definition: real.hpp:1235
friend T & operator/=(T &x, const real &r)
Generic in-place division by piranha::real.
Definition: real.hpp:1365
real binomial(const real &) const
Binomial coefficient.
Definition: real.hpp:2214
void operator()(real &x, const real &y, const real &z) const
Call operator.
Definition: real.hpp:2136
auto operator/=(const T &x) -> decltype(this->in_place_div(x))
In-place division.
Definition: real.hpp:1344
real()
Default constructor.
Definition: real.hpp:740
friend auto operator==(const T &x, const U &y) -> decltype(real::binary_equality(x, y))
Generic equality operator involving piranha::real.
Definition: real.hpp:1443
Type trait to detect piranha::safe_cast().
Definition: safe_cast.hpp:237
std::remove_extent<::mpfr_t >::type * get_mpfr_t()
Get a mutable reference to the internal mpfr_t instance.
Definition: real.hpp:1734
real operator+() const
Identity operator.
Definition: real.hpp:1141
real & operator=(const T &x)
Generic assignment operator.
Definition: real.hpp:931
void boost_save(Archive &ar, const T &x)
Save to Boost archive.
Definition: s11n.hpp:328
bool is_zero() const
Test for zero.
Definition: real.hpp:1000
friend auto operator/(const T &x, const U &y) -> decltype(real::binary_div(x, y))
Generic binary division involving piranha::real.
Definition: real.hpp:1387
real gamma() const
Gamma function.
Definition: real.hpp:1585
T operator()(const real &r) const
Call operator, real to integral overload.
Definition: real.hpp:2293
friend auto operator+(const T &x, const U &y) -> decltype(real::binary_add(x, y))
Generic binary addition involving piranha::real.
Definition: real.hpp:1133
real operator()(const T2 &r, const real &x) const
Call operator, real exponent overload.
Definition: real.hpp:1998
static const bool value
Value of the type trait.
void msgpack_convert(const msgpack::object &o, msgpack_format f)
Convert from msgpack object.
Definition: real.hpp:1841
#define PIRANHA_TT_CHECK(tt,...)
Macro for static type trait checks.
Default functor for the implementation of piranha::math::abs().
Definition: math.hpp:947
friend std::istream & operator>>(std::istream &is, real &r)
Overload input stream operator for piranha::real.
Definition: real.hpp:1721
real & operator--()
Prefix decrement.
Definition: real.hpp:1247
Exception to signal failure in piranha::safe_cast().
Definition: safe_cast.hpp:53
detail::math_sin_type< T > sin(const T &x)
Sine.
Definition: math.hpp:622
real abs() const
Absolute value.
Definition: real.hpp:1618
real operator++(int)
Suffix increment.
Definition: real.hpp:1161
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219