1 /* Copyright 2009-2016 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 "binomial.hpp"
47 #include "config.hpp"
48 #include "detail/demangle.hpp"
49 #include "detail/is_digit.hpp"
50 #include "detail/mpfr.hpp"
51 #include "detail/real_fwd.hpp"
52 #include "exceptions.hpp"
53 #include "is_cf.hpp"
54 #include "math.hpp"
55 #include "mp_integer.hpp"
56 #include "mp_rational.hpp"
57 #include "pow.hpp"
58 #include "s11n.hpp"
59 #include "safe_cast.hpp"
60 #include "type_traits.hpp"
61 
62 #undef mpfr_set
63 
64 namespace piranha
65 {
66 
67 namespace detail
68 {
69 
70 template <typename = int>
71 struct real_base {
72     // Default rounding mode.
73     // All operations will use the MPFR_RNDN (round to nearest) rounding mode.
74     static const ::mpfr_rnd_t default_rnd = MPFR_RNDN;
75     // Default significand precision.
76     // The precision is the number of bits used to represent the significand of a floating-point number.
77     // This default value is equivalent to the IEEE 754 quadruple-precision binary floating-point format.
78     static const ::mpfr_prec_t default_prec = 113;
79 };
80 
81 template <typename T>
82 const ::mpfr_rnd_t real_base<T>::default_rnd;
83 
84 template <typename T>
85 const ::mpfr_prec_t real_base<T>::default_prec;
86 
87 // Types interoperable with real.
88 template <typename T>
89 struct is_real_interoperable_type {
90     static const bool value = detail::is_mp_integer_interoperable_type<T>::value || detail::is_mp_integer<T>::value
91                               || detail::is_mp_rational<T>::value;
92 };
93 }
94 
95 /// Arbitrary precision floating-point class.
96 /**
97  * This class represents floating-point ("real") numbers of arbitrary size (i.e., the size is limited only by the
98  * available memory).
99  * The implementation consists of a C++ wrapper around the \p mpfr_t type from the multiprecision MPFR library. Real
100  * numbers
101  * are represented in binary format and they consist of an arbitrary-size significand coupled to a fixed-size exponent.
102  *
103  * Unless noted otherwise, this implementation always uses the \p MPFR_RNDN (round to nearest) rounding mode for all
104  * operations.
105  *
106  * ## Interoperability with other types ##
107  *
108  * This class interoperates with the same types as piranha::mp_integer and piranha::mp_rational,
109  * plus piranha::mp_integer and piranha::mp_rational themselves.
110  * The same caveats with respect to interoperability with floating-point types mentioned in the documentation
111  * of piranha::mp_integer apply.
112  *
113  * ## Exception safety guarantee ##
114  *
115  * Unless noted otherwise, this class provides the strong exception safety guarantee for all operations.
116  * In case of memory allocation errors by GMP/MPFR routines, the program will terminate.
117  *
118  * ## Move semantics ##
119  *
120  * Move construction and move assignment will leave the moved-from object in a state that is destructible and
121  * assignable.
122  *
123  * @see http://www.mpfr.org
124  */
125 // NOTES:
126 // - if we overhaul the tests, put random precision values as well.
127 // - maybe we should have a setter as well for the global default precision. It would need to be an atomic
128 //   variable, and we need perf measures to understand the performance impact of this.
129 // - For series evaluation, we need to be careful performance-wise with the possible conversions that might go
130 //   on when mixing real with other types. E.g., pow(real,int) when evaluating polynomials. We need to make sure
131 //   the conversions are as fast as possible.
132 // - At the moment, this class is technically not sortable because moved-from reals cannot be compared. For use in
133 //   std::sort, we should add special casing for moved-from objects. See:
134 //   http://stackoverflow.com/questions/26579132/what-is-the-post-condition-of-a-move-constructor
135 class real : public detail::real_base<>
136 {
137     // Shortcut for interop type detector.
138     template <typename T>
139     using is_interoperable_type = detail::is_real_interoperable_type<T>;
140     // Enabler for generic ctor.
141     template <typename T>
142     using generic_ctor_enabler = typename std::enable_if<is_interoperable_type<T>::value, int>::type;
143     // Enabler for conversion operator.
144     template <typename T>
145     using cast_enabler = generic_ctor_enabler<T>;
146     // Enabler for in-place arithmetic operations with interop on the left.
147     template <typename T>
148     using generic_in_place_enabler =
149         typename std::enable_if<is_interoperable_type<T>::value && !std::is_const<T>::value, int>::type;
150     // Precision check.
prec_check(const::mpfr_prec_t & prec)151     static void prec_check(const ::mpfr_prec_t &prec)
152     {
153         if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
154             piranha_throw(std::invalid_argument, "invalid significand precision requested");
155         }
156     }
157     // Construction.
construct_from_string(const char * str,const::mpfr_prec_t & prec)158     void construct_from_string(const char *str, const ::mpfr_prec_t &prec)
159     {
160         prec_check(prec);
161         ::mpfr_init2(m_value, prec);
162         const int retval = ::mpfr_set_str(m_value, str, 10, default_rnd);
163         if (retval != 0) {
164             ::mpfr_clear(m_value);
165             piranha_throw(std::invalid_argument, "invalid string input for real");
166         }
167     }
168     // The idea here is that we use the largest integral and fp types supported by the MPFR api for construction,
169     // and down-cast as needed.
170     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
construct_from_generic(const T & x)171     void construct_from_generic(const T &x)
172     {
173         ::mpfr_set_ld(m_value, static_cast<long double>(x), default_rnd);
174     }
175     template <typename T,
176               typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, int>::type = 0>
construct_from_generic(const T & si)177     void construct_from_generic(const T &si)
178     {
179         ::mpfr_set_sj(m_value, static_cast<std::intmax_t>(si), default_rnd);
180     }
181     template <typename T,
182               typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, int>::type = 0>
construct_from_generic(const T & ui)183     void construct_from_generic(const T &ui)
184     {
185         ::mpfr_set_uj(m_value, static_cast<std::uintmax_t>(ui), default_rnd);
186     }
187     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
construct_from_generic(const T & n)188     void construct_from_generic(const T &n)
189     {
190         auto v = n.get_mpz_view();
191         ::mpfr_set_z(m_value, v, default_rnd);
192     }
193     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
construct_from_generic(const T & q)194     void construct_from_generic(const T &q)
195     {
196         auto v = q.get_mpq_view();
197         ::mpfr_set_q(m_value, v, default_rnd);
198     }
199     // Assignment.
assign_from_string(const char * str)200     void assign_from_string(const char *str)
201     {
202         piranha_assert(m_value->_mpfr_d);
203         const int retval = ::mpfr_set_str(m_value, str, 10, default_rnd);
204         if (retval != 0) {
205             // Reset the internal value, as it might have been changed by ::mpfr_set_str().
206             ::mpfr_set_zero(m_value, 0);
207             piranha_throw(std::invalid_argument, "invalid string input for real");
208         }
209     }
210     // Conversion.
211     template <typename T>
convert_to_impl() const212     typename std::enable_if<std::is_same<T, bool>::value, T>::type convert_to_impl() const
213     {
214         return (sign() != 0);
215     }
216     template <typename T>
convert_to_impl() const217     typename std::enable_if<detail::is_mp_integer<T>::value, T>::type convert_to_impl() const
218     {
219         if (is_nan() || is_inf()) {
220             piranha_throw(std::overflow_error, "cannot convert non-finite real to an integral value");
221         }
222         T retval;
223         retval.promote();
224         // Explicitly request rounding to zero in this case.
225         ::mpfr_get_z(&retval.m_int.g_dy(), m_value, MPFR_RNDZ);
226         // NOTE: demote candidate.
227         return retval;
228     }
229     template <typename T>
230     typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, T>::type
convert_to_impl() const231     convert_to_impl() const
232     {
233         // NOTE: of course, this can be optimised by avoiding going through the integer conversion and
234         // using directly the MPFR functions.
235         return static_cast<T>(static_cast<integer>(*this));
236     }
237     template <typename T>
convert_to_impl() const238     typename std::enable_if<std::is_floating_point<T>::value, T>::type convert_to_impl() const
239     {
240         if (is_nan()) {
241             if (std::numeric_limits<T>::has_quiet_NaN) {
242                 return std::numeric_limits<T>::quiet_NaN();
243             } else {
244                 piranha_throw(std::overflow_error, "cannot convert NaN to floating-point type");
245             }
246         }
247         if (is_inf()) {
248             piranha_assert(sign() != 0);
249             if (std::numeric_limits<T>::has_infinity && sign() > 0) {
250                 return std::numeric_limits<T>::infinity();
251             } else if (std::numeric_limits<T>::has_infinity && sign() < 0) {
252                 return std::copysign(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::lowest());
253             } else {
254                 piranha_throw(std::overflow_error, "cannot convert infinity to floating-point type");
255             }
256         }
257         if (std::is_same<T, long double>::value) {
258             return static_cast<T>(::mpfr_get_ld(m_value, default_rnd));
259         }
260         if (std::is_same<T, double>::value) {
261             return static_cast<T>(::mpfr_get_d(m_value, default_rnd));
262         }
263         return static_cast<T>(::mpfr_get_flt(m_value, default_rnd));
264     }
265     // Smart pointer to handle the string output from mpfr.
266     typedef std::unique_ptr<char, void (*)(char *)> smart_mpfr_str;
267     template <typename T>
convert_to_impl() const268     typename std::enable_if<detail::is_mp_rational<T>::value, T>::type convert_to_impl() const
269     {
270         if (is_nan()) {
271             piranha_throw(std::overflow_error, "cannot convert NaN to rational");
272         }
273         if (is_inf()) {
274             piranha_throw(std::overflow_error, "cannot convert infinity to rational");
275         }
276         if (sign() == 0) {
277             return T{};
278         }
279         // Get string representation.
280         ::mpfr_exp_t exp(0);
281         char *cptr = ::mpfr_get_str(nullptr, &exp, 10, 0, m_value, default_rnd);
282         if (unlikely(!cptr)) {
283             piranha_throw(std::overflow_error,
284                           "error in conversion of real to rational: the call to the MPFR function failed");
285         }
286         smart_mpfr_str str_ptr(cptr, ::mpfr_free_str);
287         // Transform into fraction.
288         std::size_t digits = 0u;
289         for (; *cptr != '\0'; ++cptr) {
290             if (detail::is_digit(*cptr)) {
291                 ++digits;
292             }
293         }
294         if (!digits) {
295             piranha_throw(std::overflow_error, "error in conversion of real to rational: invalid number of digits");
296         }
297         // NOTE: here the only exception that can be thrown is when raising to a power
298         // that cannot be represented by unsigned long.
299         try {
300             T retval(str_ptr.get());
301             // NOTE: possible optimizations here include going through direct GMP routines.
302             retval *= T(1, 10).pow(digits);
303             retval *= T(10).pow(exp);
304             return retval;
305         } catch (...) {
306             piranha_throw(std::overflow_error, "error in conversion of real to rational: exponent is too large");
307         }
308     }
309     // In-place addition.
310     // NOTE: all sorts of optimisations, here and in binary add, are possible (e.g., steal from rvalue ref,
311     // avoid setting precision twice in binary operators, etc.). For the moment we keep it basic.
in_place_add(const real & r)312     real &in_place_add(const real &r)
313     {
314         if (r.get_prec() > get_prec()) {
315             // Re-init this with the prec of r.
316             *this = real{*this, r.get_prec()};
317         }
318         ::mpfr_add(m_value, m_value, r.m_value, default_rnd);
319         return *this;
320     }
321     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
in_place_add(const T & q)322     real &in_place_add(const T &q)
323     {
324         auto v = q.get_mpq_view();
325         ::mpfr_add_q(m_value, m_value, v, default_rnd);
326         return *this;
327     }
328     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
in_place_add(const T & n)329     real &in_place_add(const T &n)
330     {
331         auto v = n.get_mpz_view();
332         ::mpfr_add_z(m_value, m_value, v, default_rnd);
333         return *this;
334     }
335     // NOTE: possible optimisations here.
336     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
in_place_add(const T & n)337     real &in_place_add(const T &n)
338     {
339         return in_place_add(integer(n));
340     }
341     // NOTE: possible optimisations here as well.
342     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
in_place_add(const T & x)343     real &in_place_add(const T &x)
344     {
345         // Construct real with the same precision as this, then add.
346         return in_place_add(real{x, get_prec()});
347     }
348     // Binary add.
binary_add(const real & a,const real & b)349     static real binary_add(const real &a, const real &b)
350     {
351         real retval{a};
352         retval += b;
353         return retval;
354     }
355     // Single implementation for all interoperable types.
356     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_add(const real & a,const T & b)357     static real binary_add(const real &a, const T &b)
358     {
359         real retval{a};
360         retval += b;
361         return retval;
362     }
363     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_add(const T & a,const real & b)364     static real binary_add(const T &a, const real &b)
365     {
366         return binary_add(b, a);
367     }
368     // In-place subtraction.
in_place_sub(const real & r)369     real &in_place_sub(const real &r)
370     {
371         if (r.get_prec() > get_prec()) {
372             *this = real{*this, r.get_prec()};
373         }
374         ::mpfr_sub(m_value, m_value, r.m_value, default_rnd);
375         return *this;
376     }
377     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
in_place_sub(const T & q)378     real &in_place_sub(const T &q)
379     {
380         auto v = q.get_mpq_view();
381         ::mpfr_sub_q(m_value, m_value, v, default_rnd);
382         return *this;
383     }
384     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
in_place_sub(const T & n)385     real &in_place_sub(const T &n)
386     {
387         auto v = n.get_mpz_view();
388         ::mpfr_sub_z(m_value, m_value, v, default_rnd);
389         return *this;
390     }
391     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
in_place_sub(const T & n)392     real &in_place_sub(const T &n)
393     {
394         return in_place_sub(integer(n));
395     }
396     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
in_place_sub(const T & x)397     real &in_place_sub(const T &x)
398     {
399         return in_place_sub(real{x, get_prec()});
400     }
401     // Binary sub.
binary_sub(const real & a,const real & b)402     static real binary_sub(const real &a, const real &b)
403     {
404         real retval{a};
405         retval -= b;
406         return retval;
407     }
408     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_sub(const real & a,const T & b)409     static real binary_sub(const real &a, const T &b)
410     {
411         real retval{a};
412         retval -= b;
413         return retval;
414     }
415     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_sub(const T & a,const real & b)416     static real binary_sub(const T &a, const real &b)
417     {
418         auto retval = binary_sub(b, a);
419         retval.negate();
420         return retval;
421     }
422     // In-place multiplication.
in_place_mul(const real & r)423     real &in_place_mul(const real &r)
424     {
425         if (r.get_prec() > get_prec()) {
426             *this = real{*this, r.get_prec()};
427         }
428         ::mpfr_mul(m_value, m_value, r.m_value, default_rnd);
429         return *this;
430     }
431     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
in_place_mul(const T & q)432     real &in_place_mul(const T &q)
433     {
434         auto v = q.get_mpq_view();
435         ::mpfr_mul_q(m_value, m_value, v, default_rnd);
436         return *this;
437     }
438     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
in_place_mul(const T & n)439     real &in_place_mul(const T &n)
440     {
441         auto v = n.get_mpz_view();
442         ::mpfr_mul_z(m_value, m_value, v, default_rnd);
443         return *this;
444     }
445     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
in_place_mul(const T & n)446     real &in_place_mul(const T &n)
447     {
448         return in_place_mul(integer(n));
449     }
450     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
in_place_mul(const T & x)451     real &in_place_mul(const T &x)
452     {
453         return in_place_mul(real{x, get_prec()});
454     }
455     // Binary mul.
binary_mul(const real & a,const real & b)456     static real binary_mul(const real &a, const real &b)
457     {
458         real retval{a};
459         retval *= b;
460         return retval;
461     }
462     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_mul(const real & a,const T & b)463     static real binary_mul(const real &a, const T &b)
464     {
465         real retval{a};
466         retval *= b;
467         return retval;
468     }
469     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_mul(const T & a,const real & b)470     static real binary_mul(const T &a, const real &b)
471     {
472         return binary_mul(b, a);
473     }
474     // In-place division.
in_place_div(const real & r)475     real &in_place_div(const real &r)
476     {
477         if (r.get_prec() > get_prec()) {
478             *this = real{*this, r.get_prec()};
479         }
480         ::mpfr_div(m_value, m_value, r.m_value, default_rnd);
481         return *this;
482     }
483     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
in_place_div(const T & q)484     real &in_place_div(const T &q)
485     {
486         auto v = q.get_mpq_view();
487         ::mpfr_div_q(m_value, m_value, v, default_rnd);
488         return *this;
489     }
490     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
in_place_div(const T & n)491     real &in_place_div(const T &n)
492     {
493         auto v = n.get_mpz_view();
494         ::mpfr_div_z(m_value, m_value, v, default_rnd);
495         return *this;
496     }
497     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
in_place_div(const T & n)498     real &in_place_div(const T &n)
499     {
500         return in_place_div(integer(n));
501     }
502     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
in_place_div(const T & x)503     real &in_place_div(const T &x)
504     {
505         return in_place_div(real{x, get_prec()});
506     }
507     // Binary div.
binary_div(const real & a,const real & b)508     static real binary_div(const real &a, const real &b)
509     {
510         real retval{a};
511         retval /= b;
512         return retval;
513     }
514     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_div(const real & a,const T & b)515     static real binary_div(const real &a, const T &b)
516     {
517         real retval{a};
518         retval /= b;
519         return retval;
520     }
521     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_div(const T & a,const real & b)522     static real binary_div(const T &a, const real &b)
523     {
524         // Create with same precision as b.
525         real retval{a, b.get_prec()};
526         retval /= b;
527         return retval;
528     }
529     // Equality.
binary_equality(const real & r1,const real & r2)530     static bool binary_equality(const real &r1, const real &r2)
531     {
532         return (::mpfr_equal_p(r1.m_value, r2.m_value) != 0);
533     }
534     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
binary_equality(const real & r,const T & n)535     static bool binary_equality(const real &r, const T &n)
536     {
537         if (r.is_nan()) {
538             return false;
539         }
540         auto v = n.get_mpz_view();
541         return (::mpfr_cmp_z(r.m_value, v) == 0);
542     }
543     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
binary_equality(const real & r,const T & q)544     static bool binary_equality(const real &r, const T &q)
545     {
546         if (r.is_nan()) {
547             return false;
548         }
549         auto v = q.get_mpq_view();
550         return (::mpfr_cmp_q(r.m_value, v) == 0);
551     }
552     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
binary_equality(const real & r,const T & n)553     static bool binary_equality(const real &r, const T &n)
554     {
555         if (r.is_nan()) {
556             return false;
557         }
558         return r == integer(n);
559     }
560     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
binary_equality(const real & r,const T & x)561     static bool binary_equality(const real &r, const T &x)
562     {
563         if (r.is_nan() || std::isnan(x)) {
564             return false;
565         }
566         return r == real{x, r.get_prec()};
567     }
568     // NOTE: this is the reverse of above.
569     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_equality(const T & x,const real & r)570     static bool binary_equality(const T &x, const real &r)
571     {
572         return binary_equality(r, x);
573     }
574     // Binary less-than.
binary_less_than(const real & r1,const real & r2)575     static bool binary_less_than(const real &r1, const real &r2)
576     {
577         return (::mpfr_less_p(r1.m_value, r2.m_value) != 0);
578     }
579     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
binary_less_than(const real & r,const T & q)580     static bool binary_less_than(const real &r, const T &q)
581     {
582         auto v = q.get_mpq_view();
583         return (::mpfr_cmp_q(r.m_value, v) < 0);
584     }
585     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
binary_less_than(const real & r,const T & n)586     static bool binary_less_than(const real &r, const T &n)
587     {
588         auto v = n.get_mpz_view();
589         return (::mpfr_cmp_z(r.m_value, v) < 0);
590     }
591     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
binary_less_than(const real & r,const T & n)592     static bool binary_less_than(const real &r, const T &n)
593     {
594         return r < integer(n);
595     }
596     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
binary_less_than(const real & r,const T & x)597     static bool binary_less_than(const real &r, const T &x)
598     {
599         return r < real{x, r.get_prec()};
600     }
601     // Binary less-than or equal.
binary_leq(const real & r1,const real & r2)602     static bool binary_leq(const real &r1, const real &r2)
603     {
604         return (::mpfr_lessequal_p(r1.m_value, r2.m_value) != 0);
605     }
606     template <typename T, typename std::enable_if<detail::is_mp_rational<T>::value, int>::type = 0>
binary_leq(const real & r,const T & q)607     static bool binary_leq(const real &r, const T &q)
608     {
609         auto v = q.get_mpq_view();
610         return (::mpfr_cmp_q(r.m_value, v) <= 0);
611     }
612     template <typename T, typename std::enable_if<detail::is_mp_integer<T>::value, int>::type = 0>
binary_leq(const real & r,const T & n)613     static bool binary_leq(const real &r, const T &n)
614     {
615         auto v = n.get_mpz_view();
616         return (::mpfr_cmp_z(r.m_value, v) <= 0);
617     }
618     template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
binary_leq(const real & r,const T & n)619     static bool binary_leq(const real &r, const T &n)
620     {
621         return r <= integer(n);
622     }
623     template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
binary_leq(const real & r,const T & x)624     static bool binary_leq(const real &r, const T &x)
625     {
626         return r <= real{x, r.get_prec()};
627     }
628     // Inverse forms of less-than and leq.
629     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_less_than(const T & x,const real & r)630     static bool binary_less_than(const T &x, const real &r)
631     {
632         return !binary_leq(r, x);
633     }
634     template <typename T, typename std::enable_if<is_interoperable_type<T>::value, int>::type = 0>
binary_leq(const T & x,const real & r)635     static bool binary_leq(const T &x, const real &r)
636     {
637         return !binary_less_than(r, x);
638     }
639     // NOTE: we need to handle separately the NaNs as we cannot resort to the inversion of the comparison operators for
640     // them.
check_nan(const real & r)641     static bool check_nan(const real &r)
642     {
643         return r.is_nan();
644     }
645     template <typename T>
check_nan(const T & x,typename std::enable_if<std::is_floating_point<T>::value>::type * =nullptr)646     static bool check_nan(const T &x, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr)
647     {
648         return std::isnan(x);
649     }
650     template <typename T>
check_nan(const T &,typename std::enable_if<!std::is_floating_point<T>::value>::type * =nullptr)651     static bool check_nan(const T &, typename std::enable_if<!std::is_floating_point<T>::value>::type * = nullptr)
652     {
653         return false;
654     }
655     template <typename T, typename U>
is_nan_comparison(const T & a,const U & b)656     static bool is_nan_comparison(const T &a, const U &b)
657     {
658         return (check_nan(a) || check_nan(b));
659     }
660     // Serialization support.
661     friend class boost::serialization::access;
662     // Utility function to infer the size (in number of limbs) from the precision.
size_from_prec(::mpfr_prec_t prec)663     static ::mpfr_prec_t size_from_prec(::mpfr_prec_t prec)
664     {
665         const ::mpfr_prec_t q = prec / ::mp_bits_per_limb, r = prec % ::mp_bits_per_limb;
666         return q + (r != 0);
667     }
668     // Portable s11n.
669     template <class Archive, enable_if_t<!std::is_same<Archive, boost::archive::binary_oarchive>::value, int> = 0>
save(Archive & ar,unsigned) const670     void save(Archive &ar, unsigned) const
671     {
672         // NOTE: like in mp_integer, the performance here can be improved significantly.
673         std::ostringstream oss;
674         oss << *this;
675         auto prec = get_prec();
676         auto s = oss.str();
677         piranha::boost_save(ar, prec);
678         piranha::boost_save(ar, s);
679     }
680     template <class Archive, enable_if_t<!std::is_same<Archive, boost::archive::binary_iarchive>::value, int> = 0>
load(Archive & ar,unsigned)681     void load(Archive &ar, unsigned)
682     {
683         ::mpfr_prec_t prec;
684         PIRANHA_MAYBE_TLS std::string s;
685         piranha::boost_load(ar, prec);
686         piranha::boost_load(ar, s);
687         *this = real(s, prec);
688     }
689     // Binary s11n.
690     template <class Archive, enable_if_t<std::is_same<Archive, boost::archive::binary_oarchive>::value, int> = 0>
save(Archive & ar,unsigned) const691     void save(Archive &ar, unsigned) const
692     {
693         piranha::boost_save(ar, m_value->_mpfr_prec);
694         piranha::boost_save(ar, m_value->_mpfr_sign);
695         piranha::boost_save(ar, m_value->_mpfr_exp);
696         const ::mpfr_prec_t s = size_from_prec(m_value->_mpfr_prec);
697         // NOTE: no need to save the size, as it can be recovered from the prec.
698         for (::mpfr_prec_t i = 0; i < s; ++i) {
699             piranha::boost_save(ar, m_value->_mpfr_d[i]);
700         }
701     }
702     template <class Archive, enable_if_t<std::is_same<Archive, boost::archive::binary_iarchive>::value, int> = 0>
load(Archive & ar,unsigned)703     void load(Archive &ar, unsigned)
704     {
705         // First we recover the non-limb members.
706         ::mpfr_prec_t prec;
707         decltype(m_value->_mpfr_sign) sign;
708         decltype(m_value->_mpfr_exp) exp;
709         piranha::boost_load(ar, prec);
710         piranha::boost_load(ar, sign);
711         piranha::boost_load(ar, exp);
712         // Recover the size in limbs from prec.
713         const ::mpfr_prec_t s = size_from_prec(prec);
714         // Set the precision.
715         set_prec(prec);
716         piranha_assert(m_value->_mpfr_prec == prec);
717         m_value->_mpfr_sign = sign;
718         m_value->_mpfr_exp = exp;
719         try {
720             // NOTE: protect in try/catch as in theory boost_load() could throw even
721             // in case of valid archive (e.g., memory errors maybe?) and we want
722             // to deal with this case.
723             for (::mpfr_prec_t i = 0; i < s; ++i) {
724                 piranha::boost_load(ar, *(m_value->_mpfr_d + i));
725             }
726         } catch (...) {
727             // Set to zero before re-throwing.
728             ::mpfr_set_ui(m_value, 0u, default_rnd);
729             throw;
730         }
731     }
732     BOOST_SERIALIZATION_SPLIT_MEMBER()
733 public:
734     /// Default constructor.
735     /**
736      * Will initialize the number to zero, using real::default_prec as significand precision.
737      */
real()738     real()
739     {
740         ::mpfr_init2(m_value, default_prec);
741         ::mpfr_set_zero(m_value, 0);
742     }
743     /// Copy constructor.
744     /**
745      * Will deep-copy \p other.
746      *
747      * @param other real to be copied.
748      */
real(const real & other)749     real(const real &other)
750     {
751         // Init with the same precision as other, and then set.
752         ::mpfr_init2(m_value, other.get_prec());
753         ::mpfr_set(m_value, other.m_value, default_rnd);
754     }
755     /// Move constructor.
756     /**
757      * @param other real to be moved.
758      */
real(real && other)759     real(real &&other) noexcept
760     {
761         m_value->_mpfr_prec = other.m_value->_mpfr_prec;
762         m_value->_mpfr_sign = other.m_value->_mpfr_sign;
763         m_value->_mpfr_exp = other.m_value->_mpfr_exp;
764         m_value->_mpfr_d = other.m_value->_mpfr_d;
765         // Erase other.
766         other.m_value->_mpfr_prec = 0;
767         other.m_value->_mpfr_sign = 0;
768         other.m_value->_mpfr_exp = 0;
769         other.m_value->_mpfr_d = nullptr;
770     }
771     /// Constructor from C string.
772     /**
773      * Will use the string \p str and precision \p prec to initialize the number.
774      * The expected string format, assuming representation in base 10, is described in the MPFR documentation.
775      *
776      * @param str string representation of the real number.
777      * @param prec desired significand precision.
778      *
779      * @throws std::invalid_argument if the conversion from string fails or if the requested significand precision
780      * is not within the range allowed by the MPFR library.
781      */
real(const char * str,const::mpfr_prec_t & prec=default_prec)782     explicit real(const char *str, const ::mpfr_prec_t &prec = default_prec)
783     {
784         construct_from_string(str, prec);
785     }
786     /// Constructor from C++ string.
787     /**
788      * Equivalent to the constructor from C string.
789      *
790      * @param str string representation of the real number.
791      * @param prec desired significand precision.
792      *
793      * @throws unspecified any exception thrown by the constructor from C string.
794      */
real(const std::string & str,const::mpfr_prec_t & prec=default_prec)795     explicit real(const std::string &str, const ::mpfr_prec_t &prec = default_prec)
796     {
797         construct_from_string(str.c_str(), prec);
798     }
799     /// Copy constructor with different precision.
800     /**
801      * \p this will be first initialised with precision \p prec, and then \p other will be assigned to \p this.
802      *
803      * @param other real to be copied.
804      * @param prec desired significand precision.
805      *
806      * @throws std::invalid_argument if the requested significand precision
807      * is not within the range allowed by the MPFR library.
808      */
real(const real & other,const::mpfr_prec_t & prec)809     explicit real(const real &other, const ::mpfr_prec_t &prec)
810     {
811         prec_check(prec);
812         ::mpfr_init2(m_value, prec);
813         ::mpfr_set(m_value, other.m_value, default_rnd);
814     }
815     /// Generic constructor.
816     /**
817      * \note
818      * This constructor is enabled only if \p T is an interoperable type.
819      *
820      * @param x object used to construct \p this.
821      * @param prec desired significand precision.
822      *
823      * @throws std::invalid_argument if the requested significand precision
824      * is not within the range allowed by the MPFR library.
825      */
826     template <typename T, typename = generic_ctor_enabler<T>>
real(const T & x,const::mpfr_prec_t & prec=default_prec)827     explicit real(const T &x, const ::mpfr_prec_t &prec = default_prec)
828     {
829         prec_check(prec);
830         ::mpfr_init2(m_value, prec);
831         construct_from_generic(x);
832     }
833     /// Destructor.
834     /**
835      * Will clear the internal MPFR variable.
836      */
837     ~real();
838     /// Copy assignment operator.
839     /**
840      * The assignment operation will deep-copy \p other (i.e., including its precision).
841      *
842      * @param other real to be copied.
843      *
844      * @return reference to \p this.
845      */
operator =(const real & other)846     real &operator=(const real &other)
847     {
848         if (this != &other) {
849             // Handle assignment to moved-from objects.
850             if (m_value->_mpfr_d) {
851                 // Copy the precision. This will also reset the internal value.
852                 set_prec(other.get_prec());
853             } else {
854                 piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
855                 // Reinit before setting.
856                 ::mpfr_init2(m_value, other.get_prec());
857             }
858             ::mpfr_set(m_value, other.m_value, default_rnd);
859         }
860         return *this;
861     }
862     /// Move assignment operator.
863     /**
864      * @param other real to be moved.
865      *
866      * @return reference to \p this.
867      */
operator =(real && other)868     real &operator=(real &&other) noexcept
869     {
870         // NOTE: swap() already has the check for this.
871         swap(other);
872         return *this;
873     }
874     /// Assignment operator from C++ string.
875     /**
876      * The implementation is equivalent to the assignment operator from C string.
877      *
878      * @param str string representation of the real to be assigned.
879      *
880      * @return reference to \p this.
881      *
882      * @throws unspecified any exception thrown by the assignment operator from C string.
883      */
operator =(const std::string & str)884     real &operator=(const std::string &str)
885     {
886         return operator=(str.c_str());
887     }
888     /// Assignment operator from C string.
889     /**
890      * The parsing rules are the same as in the constructor from string. The precision of \p this
891      * will not be changed by the assignment operation, unless \p this was the target of a move operation that
892      * left it in an uninitialised state.
893      * In that case, \p this will be re-initialised with the default precision.
894      *
895      * In case \p str is malformed, before an exception is thrown the value of \p this will be reset to zero.
896      *
897      * @param str string representation of the real to be assigned.
898      *
899      * @return reference to \p this.
900      *
901      * @throws std::invalid_argument if the conversion from string fails.
902      */
operator =(const char * str)903     real &operator=(const char *str)
904     {
905         // Handle moved-from objects.
906         if (m_value->_mpfr_d) {
907             assign_from_string(str);
908         } else {
909             piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
910             construct_from_string(str, default_prec);
911         }
912         return *this;
913     }
914     /// Generic assignment operator.
915     /**
916      * \note
917      * This assignment operator is enabled only if \p T is an interoperable type.
918      *
919      * The precision of \p this
920      * will not be changed by the assignment operation, unless \p this was the target of a move operation that
921      * left it in an uninitialised state.
922      * In that case, \p this will be re-initialised with the default precision.
923      *
924      * @param x object that will be assigned to \p this.
925      *
926      * @return reference to \p this.
927      */
928     template <typename T, typename = generic_ctor_enabler<T>>
operator =(const T & x)929     real &operator=(const T &x)
930     {
931         if (!m_value->_mpfr_d) {
932             piranha_assert(!m_value->_mpfr_prec && !m_value->_mpfr_sign && !m_value->_mpfr_exp);
933             // Re-init with default prec if it was moved-from.
934             ::mpfr_init2(m_value, default_prec);
935         }
936         // NOTE: all construct_from_generic() methods here are really assignments.
937         construct_from_generic(x);
938         return *this;
939     }
940     /// Conversion operator.
941     /**
942      * \note
943      * This operator is enabled only if \p T is an interoperable type.
944      *
945      * Extract an instance of type \p T from \p this.
946      *
947      * Conversion to \p bool is always successful, and returns <tt>sign() != 0</tt>.
948      * Conversion to the other integral types is truncated (i.e., rounded to zero), its success depending on whether or
949      * not the target type can represent the truncated value.
950      *
951      * Conversion to floating point types is exact if the target type can represent exactly the current value.
952      * If that is not the case, the output value will be the nearest adjacent. If \p this is not finite,
953      * corresponding non-finite values will be produced if the floating-point type supports them, otherwise
954      * an error will be produced.
955      *
956      * Conversion of finite values to piranha::mp_rational will be exact. Conversion of non-finite values will result in
957      * runtime errors.
958      *
959      * @return result of the conversion to target type T.
960      *
961      * @throws std::overflow_error if the conversion fails in one of the ways described above.
962      */
963     template <typename T, typename = cast_enabler<T>>
operator T() const964     explicit operator T() const
965     {
966         return convert_to_impl<T>();
967     }
968     /// Swap.
969     /**
970      * Swap \p this with \p other.
971      *
972      * @param other swap argument.
973      */
swap(real & other)974     void swap(real &other)
975     {
976         if (this == &other) {
977             return;
978         }
979         ::mpfr_swap(m_value, other.m_value);
980     }
981     /// Sign.
982     /**
983      * @return 1 if <tt>this > 0</tt>, 0 if <tt>this == 0</tt> and -1 if <tt>this < 0</tt>. If \p this is NaN, zero will
984      * be returned.
985      */
sign() const986     int sign() const
987     {
988         if (is_nan()) {
989             return 0;
990         } else {
991             return mpfr_sgn(m_value);
992         }
993     }
994     /// Test for zero.
995     /**
996      * @return \p true it \p this is zero, \p false otherwise.
997      */
is_zero() const998     bool is_zero() const
999     {
1000         return (mpfr_zero_p(m_value) != 0);
1001     }
1002     /// Test for NaN.
1003     /**
1004      * @return \p true if \p this is NaN, \p false otherwise.
1005      */
is_nan() const1006     bool is_nan() const
1007     {
1008         return mpfr_nan_p(m_value) != 0;
1009     }
1010     /// Test for infinity.
1011     /**
1012      * @return \p true if \p this represents infinity, \p false otherwise.
1013      */
is_inf() const1014     bool is_inf() const
1015     {
1016         return mpfr_inf_p(m_value) != 0;
1017     }
1018     /// Get precision.
1019     /**
1020      * @return the number of bits used to represent the significand of \p this.
1021      */
get_prec() const1022     ::mpfr_prec_t get_prec() const
1023     {
1024         return mpfr_get_prec(m_value);
1025     }
1026     /// Set precision.
1027     /**
1028      * Will set the significand precision of \p this to exactly \p prec bits, and reset the value of \p this to NaN.
1029      *
1030      * @param prec desired significand precision.
1031      *
1032      * @throws std::invalid_argument if the requested significand precision
1033      * is not within the range allowed by the MPFR library.
1034      */
set_prec(const::mpfr_prec_t & prec)1035     void set_prec(const ::mpfr_prec_t &prec)
1036     {
1037         prec_check(prec);
1038         ::mpfr_set_prec(m_value, prec);
1039     }
1040     /// Negate in-place.
1041     /**
1042      * Will set \p this to <tt>-this</tt>.
1043      */
negate()1044     void negate()
1045     {
1046         ::mpfr_neg(m_value, m_value, default_rnd);
1047     }
1048     /// Truncate in-place.
1049     /**
1050      * Set \p this to the next representable integer towards zero. If \p this is infinity or NaN, there will be no
1051      * effect.
1052      */
truncate()1053     void truncate()
1054     {
1055         if (is_inf() || is_nan()) {
1056             return;
1057         }
1058         ::mpfr_trunc(m_value, m_value);
1059     }
1060     /// Truncated copy.
1061     /**
1062      * @return a truncated copy of \p this.
1063      */
truncated() const1064     real truncated() const
1065     {
1066         real retval{*this};
1067         retval.truncate();
1068         return retval;
1069     }
1070     /// In-place addition.
1071     /**
1072      * \note
1073      * This operator is enabled only if \p T is an interoperable type or piranha::real.
1074      *
1075      * Add \p x to the current value of the real object.
1076      *
1077      * If the precision \p prec of \p x is greater than the precision of \p this,
1078      * the precision of \p this is changed to \p prec before the operation takes place.
1079      *
1080      * @param x argument for the addition.
1081      *
1082      * @return reference to \p this.
1083      *
1084      * @throws unspecified any exception thrown by the contructor of piranha::mp_integer, if invoked.
1085      */
1086     template <typename T>
operator +=(const T & x)1087     auto operator+=(const T &x) -> decltype(this->in_place_add(x))
1088     {
1089         return in_place_add(x);
1090     }
1091     /// Generic in-place addition with piranha::real.
1092     /**
1093      * \note
1094      * This operator is enabled only if \p T is a non-const interoperable type.
1095      *
1096      * Add a piranha::real in-place.
1097      * This method will first compute <tt>r + x</tt>, cast it back to \p T via \p static_cast and finally assign the
1098      * result to \p x.
1099      *
1100      * @param x first argument.
1101      * @param r second argument.
1102      *
1103      * @return reference to \p x.
1104      *
1105      * @throws unspecified any exception resulting from the binary operator or by casting piranha::real to \p T.
1106      */
1107     template <typename T, generic_in_place_enabler<T> = 0>
operator +=(T & x,const real & r)1108     friend T &operator+=(T &x, const real &r)
1109     {
1110         // NOTE: for the supported types, move assignment can never throw.
1111         return x = static_cast<T>(r + x);
1112     }
1113     /// Generic binary addition involving piranha::real.
1114     /**
1115      * \note
1116      * This template operator is enabled only if either:
1117      * - \p T is piranha::real and \p U is an interoperable type,
1118      * - \p U is piranha::real and \p T is an interoperable type,
1119      * - both \p T and \p U are piranha::real.
1120      *
1121      * The return type is always piranha::real.
1122      *
1123      * @param x first argument
1124      * @param y second argument.
1125      *
1126      * @return <tt>x + y</tt>.
1127      *
1128      * @throws unspecified any exception thrown by the corresponding in-place operator.
1129      */
1130     template <typename T, typename U>
operator +(const T & x,const U & y)1131     friend auto operator+(const T &x, const U &y) -> decltype(real::binary_add(x, y))
1132     {
1133         return binary_add(x, y);
1134     }
1135     /// Identity operator.
1136     /**
1137      * @return copy of \p this.
1138      */
operator +() const1139     real operator+() const
1140     {
1141         return *this;
1142     }
1143     /// Prefix increment.
1144     /**
1145      * Increment \p this by one.
1146      *
1147      * @return reference to \p this after the increment.
1148      */
operator ++()1149     real &operator++()
1150     {
1151         return operator+=(1);
1152     }
1153     /// Suffix increment.
1154     /**
1155      * Increment \p this by one and return a copy of \p this as it was before the increment.
1156      *
1157      * @return copy of \p this before the increment.
1158      */
operator ++(int)1159     real operator++(int)
1160     {
1161         const real retval(*this);
1162         ++(*this);
1163         return retval;
1164     }
1165     /// In-place subtraction.
1166     /**
1167      * \note
1168      * This operator is enabled only if \p T is an interoperable type or piranha::real.
1169      *
1170      * Subtract \p x from the current value of the real object.
1171      *
1172      * If the precision \p prec of \p x is greater than the precision of \p this,
1173      * the precision of \p this is changed to \p prec before the operation takes place.
1174      *
1175      * @param x argument for the subtraction.
1176      *
1177      * @return reference to \p this.
1178      *
1179      * @throws unspecified any exception thrown by the contructor of piranha::mp_integer, if invoked.
1180      */
1181     template <typename T>
operator -=(const T & x)1182     auto operator-=(const T &x) -> decltype(this->in_place_sub(x))
1183     {
1184         return in_place_sub(x);
1185     }
1186     /// Generic in-place subtraction with piranha::real.
1187     /**
1188      * \note
1189      * This operator is enabled only if \p T is a non-const interoperable type.
1190      *
1191      * Subtract a piranha::real in-place.
1192      * This method will first compute <tt>x - r</tt>, cast it back to \p T via \p static_cast and finally assign the
1193      * result to \p x.
1194      *
1195      * @param x first argument.
1196      * @param r second argument.
1197      *
1198      * @return reference to \p x.
1199      *
1200      * @throws unspecified any exception resulting from the binary operator or by casting piranha::real to \p T.
1201      */
1202     template <typename T, generic_in_place_enabler<T> = 0>
operator -=(T & x,const real & r)1203     friend T &operator-=(T &x, const real &r)
1204     {
1205         return x = static_cast<T>(x - r);
1206     }
1207     /// Generic binary subtraction involving piranha::real.
1208     /**
1209      * \note
1210      * This template operator is enabled only if either:
1211      * - \p T is piranha::real and \p U is an interoperable type,
1212      * - \p U is piranha::real and \p T is an interoperable type,
1213      * - both \p T and \p U are piranha::real.
1214      *
1215      * The return type is always piranha::real.
1216      *
1217      * @param x first argument
1218      * @param y second argument.
1219      *
1220      * @return <tt>x - y</tt>.
1221      *
1222      * @throws unspecified any exception thrown by the corresponding in-place operator.
1223      */
1224     template <typename T, typename U>
operator -(const T & x,const U & y)1225     friend auto operator-(const T &x, const U &y) -> decltype(real::binary_sub(x, y))
1226     {
1227         return binary_sub(x, y);
1228     }
1229     /// Negated copy.
1230     /**
1231      * @return copy of \p -this.
1232      */
operator -() const1233     real operator-() const
1234     {
1235         real retval(*this);
1236         retval.negate();
1237         return retval;
1238     }
1239     /// Prefix decrement.
1240     /**
1241      * Decrement \p this by one and return.
1242      *
1243      * @return reference to \p this.
1244      */
operator --()1245     real &operator--()
1246     {
1247         return operator-=(1);
1248     }
1249     /// Suffix decrement.
1250     /**
1251      * Decrement \p this by one and return a copy of \p this as it was before the decrement.
1252      *
1253      * @return copy of \p this before the decrement.
1254      */
operator --(int)1255     real operator--(int)
1256     {
1257         const real retval(*this);
1258         --(*this);
1259         return retval;
1260     }
1261     /// In-place multiplication.
1262     /**
1263      * \note
1264      * This operator is enabled only if \p T is an interoperable type or piranha::real.
1265      *
1266      * Multiply by \p x the current value of the real object.
1267      *
1268      * If the precision \p prec of \p x is greater than the precision of \p this,
1269      * the precision of \p this is changed to \p prec before the operation takes place.
1270      *
1271      * @param x argument for the multiplication.
1272      *
1273      * @return reference to \p this.
1274      *
1275      * @throws unspecified any exception thrown by the contructor of piranha::mp_integer, if invoked.
1276      */
1277     template <typename T>
operator *=(const T & x)1278     auto operator*=(const T &x) -> decltype(this->in_place_mul(x))
1279     {
1280         return in_place_mul(x);
1281     }
1282     /// Generic in-place multiplication by piranha::real.
1283     /**
1284      * \note
1285      * This operator is enabled only if \p T is a non-const interoperable type.
1286      *
1287      * Multiply by a piranha::real in-place.
1288      * This method will first compute <tt>x * r</tt>, cast it back to \p T via \p static_cast and finally assign the
1289      * result to \p x.
1290      *
1291      * @param x first argument.
1292      * @param r second argument.
1293      *
1294      * @return reference to \p x.
1295      *
1296      * @throws unspecified any exception resulting from the binary operator or by casting piranha::real to \p T.
1297      */
1298     template <typename T, generic_in_place_enabler<T> = 0>
operator *=(T & x,const real & r)1299     friend T &operator*=(T &x, const real &r)
1300     {
1301         return x = static_cast<T>(x * r);
1302     }
1303     /// Generic binary multiplication involving piranha::real.
1304     /**
1305      * \note
1306      * This template operator is enabled only if either:
1307      * - \p T is piranha::real and \p U is an interoperable type,
1308      * - \p U is piranha::real and \p T is an interoperable type,
1309      * - both \p T and \p U are piranha::real.
1310      *
1311      * The return type is always piranha::real.
1312      *
1313      * @param x first argument
1314      * @param y second argument.
1315      *
1316      * @return <tt>x * y</tt>.
1317      *
1318      * @throws unspecified any exception thrown by the corresponding in-place operator.
1319      */
1320     template <typename T, typename U>
operator *(const T & x,const U & y)1321     friend auto operator*(const T &x, const U &y) -> decltype(real::binary_mul(x, y))
1322     {
1323         return binary_mul(x, y);
1324     }
1325     /// In-place division.
1326     /**
1327      * \note
1328      * This operator is enabled only if \p T is an interoperable type or piranha::real.
1329      *
1330      * Divide by \p x the current value of the real object.
1331      *
1332      * If the precision \p prec of \p x is greater than the precision of \p this,
1333      * the precision of \p this is changed to \p prec before the operation takes place.
1334      *
1335      * @param x argument for the division.
1336      *
1337      * @return reference to \p this.
1338      *
1339      * @throws unspecified any exception thrown by the contructor of piranha::mp_integer, if invoked.
1340      */
1341     template <typename T>
operator /=(const T & x)1342     auto operator/=(const T &x) -> decltype(this->in_place_div(x))
1343     {
1344         return in_place_div(x);
1345     }
1346     /// Generic in-place division by piranha::real.
1347     /**
1348      * \note
1349      * This operator is enabled only if \p T is a non-const interoperable type.
1350      *
1351      * Divide by a piranha::real in-place.
1352      * This method will first compute <tt>x / r</tt>, cast it back to \p T via \p static_cast and finally assign the
1353      * result to \p x.
1354      *
1355      * @param x first argument.
1356      * @param r second argument.
1357      *
1358      * @return reference to \p x.
1359      *
1360      * @throws unspecified any exception resulting from the binary operator or by casting piranha::real to \p T.
1361      */
1362     template <typename T, generic_in_place_enabler<T> = 0>
operator /=(T & x,const real & r)1363     friend T &operator/=(T &x, const real &r)
1364     {
1365         return x = static_cast<T>(x / r);
1366     }
1367     /// Generic binary division involving piranha::real.
1368     /**
1369      * \note
1370      * This template operator is enabled only if either:
1371      * - \p T is piranha::real and \p U is an interoperable type,
1372      * - \p U is piranha::real and \p T is an interoperable type,
1373      * - both \p T and \p U are piranha::real.
1374      *
1375      * The return type is always piranha::real.
1376      *
1377      * @param x first argument
1378      * @param y second argument.
1379      *
1380      * @return <tt>x / y</tt>.
1381      *
1382      * @throws unspecified any exception thrown by the corresponding in-place operator.
1383      */
1384     template <typename T, typename U>
operator /(const T & x,const U & y)1385     friend auto operator/(const T &x, const U &y) -> decltype(real::binary_div(x, y))
1386     {
1387         return binary_div(x, y);
1388     }
1389     /// Combined multiply-add.
1390     /**
1391      * Sets \p this to <tt>this + (r1 * r2)</tt>. If the precision of \p this is less than the maximum precision \p
1392      * max_prec of the two operands
1393      * \p r1 and \p r2, the precision of \p this will be set to \p max_prec before performing the operation.
1394      *
1395      * @param r1 first argument.
1396      * @param r2 second argument.
1397      *
1398      * @return reference to \p this.
1399      */
multiply_accumulate(const real & r1,const real & r2)1400     real &multiply_accumulate(const real &r1, const real &r2)
1401     {
1402         const ::mpfr_prec_t prec1 = std::max<::mpfr_prec_t>(r1.get_prec(), r2.get_prec());
1403         if (prec1 > get_prec()) {
1404             *this = real{*this, prec1};
1405         }
1406 // So the story here is that mpfr_fma has been reported to be slower than the two separate
1407 // operations. Benchmarks on fateman1 indicate this is indeed the case (3.6 vs 2.7 secs
1408 // on 4 threads). Hopefully it will be fixed in the future, for now adopt the workaround.
1409 // http://www.loria.fr/~zimmerma/mpfr-mpc-2014.html
1410 // NOTE: this optimisation requires the thread_local keyword.
1411 #if defined(PIRANHA_HAVE_THREAD_LOCAL)
1412         static thread_local real tmp;
1413         // NOTE: set the same precision as this, which is now the max precision of the 3 operands.
1414         // If we do not do this, then tmp has an undeterminate precision. Use the raw MPFR function
1415         // in order to avoid the checks in get_prec(), as we know the precision has a sane value.
1416         ::mpfr_set_prec(tmp.m_value, mpfr_get_prec(m_value));
1417         ::mpfr_mul(tmp.m_value, r1.m_value, r2.m_value, MPFR_RNDN);
1418         ::mpfr_add(m_value, m_value, tmp.m_value, MPFR_RNDN);
1419 #else
1420         ::mpfr_fma(m_value, r1.m_value, r2.m_value, m_value, default_rnd);
1421 #endif
1422         return *this;
1423     }
1424     /// Generic equality operator involving piranha::real.
1425     /**
1426      * \note
1427      * This template operator is enabled only if either:
1428      * - \p T is piranha::real and \p U is an interoperable type,
1429      * - \p U is piranha::real and \p T is an interoperable type,
1430      * - both \p T and \p U are piranha::real.
1431      *
1432      * Note that in all comparison operators, apart from piranha::real::operator!=(), if any operand is NaN \p false
1433      * will be returned.
1434      *
1435      * @param x first argument
1436      * @param y second argument.
1437      *
1438      * @return \p true if <tt>x == y</tt>, \p false otherwise.
1439      */
1440     template <typename T, typename U>
operator ==(const T & x,const U & y)1441     friend auto operator==(const T &x, const U &y) -> decltype(real::binary_equality(x, y))
1442     {
1443         return binary_equality(x, y);
1444     }
1445     /// Generic inequality operator involving piranha::real.
1446     /**
1447      * \note
1448      * This template operator is enabled only if either:
1449      * - \p T is piranha::real and \p U is an interoperable type,
1450      * - \p U is piranha::real and \p T is an interoperable type,
1451      * - both \p T and \p U are piranha::real.
1452      *
1453      * Note that in all comparison operators, apart from piranha::real::operator!=(), if any operand is NaN \p false
1454      * will be returned.
1455      *
1456      * @param x first argument
1457      * @param y second argument.
1458      *
1459      * @return \p true if <tt>x != y</tt>, \p false otherwise.
1460      */
1461     template <typename T, typename U>
operator !=(const T & x,const U & y)1462     friend auto operator!=(const T &x, const U &y) -> decltype(!real::binary_equality(x, y))
1463     {
1464         return !binary_equality(x, y);
1465     }
1466     /// Generic less-than operator involving piranha::real.
1467     /**
1468      * \note
1469      * This template operator is enabled only if either:
1470      * - \p T is piranha::real and \p U is an interoperable type,
1471      * - \p U is piranha::real and \p T is an interoperable type,
1472      * - both \p T and \p U are piranha::real.
1473      *
1474      * Note that in all comparison operators, apart from piranha::real::operator!=(), if any operand is NaN \p false
1475      * will be returned.
1476      *
1477      * @param x first argument
1478      * @param y second argument.
1479      *
1480      * @return \p true if <tt>x < y</tt>, \p false otherwise.
1481      */
1482     template <typename T, typename U>
operator <(const T & x,const U & y)1483     friend auto operator<(const T &x, const U &y) -> decltype(real::binary_less_than(x, y))
1484     {
1485         if (is_nan_comparison(x, y)) {
1486             return false;
1487         }
1488         return binary_less_than(x, y);
1489     }
1490     /// Generic less-than or equal operator involving piranha::real.
1491     /**
1492      * \note
1493      * This template operator is enabled only if either:
1494      * - \p T is piranha::real and \p U is an interoperable type,
1495      * - \p U is piranha::real and \p T is an interoperable type,
1496      * - both \p T and \p U are piranha::real.
1497      *
1498      * Note that in all comparison operators, apart from piranha::real::operator!=(), if any operand is NaN \p false
1499      * will be returned.
1500      *
1501      * @param x first argument
1502      * @param y second argument.
1503      *
1504      * @return \p true if <tt>x <= y</tt>, \p false otherwise.
1505      */
1506     template <typename T, typename U>
operator <=(const T & x,const U & y)1507     friend auto operator<=(const T &x, const U &y) -> decltype(real::binary_leq(x, y))
1508     {
1509         if (is_nan_comparison(x, y)) {
1510             return false;
1511         }
1512         return binary_leq(x, y);
1513     }
1514     /// Generic greater-than operator involving piranha::real.
1515     /**
1516      * \note
1517      * This template operator is enabled only if either:
1518      * - \p T is piranha::real and \p U is an interoperable type,
1519      * - \p U is piranha::real and \p T is an interoperable type,
1520      * - both \p T and \p U are piranha::real.
1521      *
1522      * Note that in all comparison operators, apart from piranha::real::operator!=(), if any operand is NaN \p false
1523      * will be returned.
1524      *
1525      * @param x first argument
1526      * @param y second argument.
1527      *
1528      * @return \p true if <tt>x > y</tt>, \p false otherwise.
1529      */
1530     template <typename T, typename U>
operator >(const T & x,const U & y)1531     friend auto operator>(const T &x, const U &y) -> decltype(real::binary_less_than(y, x))
1532     {
1533         if (is_nan_comparison(x, y)) {
1534             return false;
1535         }
1536         return y < x;
1537     }
1538     /// Generic greater-than or equal operator involving piranha::real.
1539     /**
1540      * \note
1541      * This template operator is enabled only if either:
1542      * - \p T is piranha::real and \p U is an interoperable type,
1543      * - \p U is piranha::real and \p T is an interoperable type,
1544      * - both \p T and \p U are piranha::real.
1545      *
1546      * Note that in all comparison operators, apart from piranha::real::operator!=(), if any operand is NaN \p false
1547      * will be returned.
1548      *
1549      * @param x first argument
1550      * @param y second argument.
1551      *
1552      * @return \p true if <tt>x >= y</tt>, \p false otherwise.
1553      */
1554     template <typename T, typename U>
operator >=(const T & x,const U & y)1555     friend auto operator>=(const T &x, const U &y) -> decltype(real::binary_leq(y, x))
1556     {
1557         if (is_nan_comparison(x, y)) {
1558             return false;
1559         }
1560         return y <= x;
1561     }
1562     /// Exponentiation.
1563     /**
1564      * The operation is carried out with the maximum precision between \p this and \p exp.
1565      *
1566      * @param exp exponent.
1567      *
1568      * @return <tt>this ** exp</tt>.
1569      */
pow(const real & exp) const1570     real pow(const real &exp) const
1571     {
1572         real retval{0, get_prec()};
1573         if (exp.get_prec() > get_prec()) {
1574             retval.set_prec(exp.get_prec());
1575         }
1576         ::mpfr_pow(retval.m_value, m_value, exp.m_value, default_rnd);
1577         return retval;
1578     }
1579     /// Gamma function.
1580     /**
1581      * @return gamma of \p this.
1582      */
gamma() const1583     real gamma() const
1584     {
1585         real retval{0, get_prec()};
1586         ::mpfr_gamma(retval.m_value, m_value, default_rnd);
1587         return retval;
1588     }
1589     /// Logarithm of the gamma function.
1590     /**
1591      * @return logarithm of the absolute value of the gamma of \p this.
1592      */
lgamma() const1593     real lgamma() const
1594     {
1595         real retval{0, get_prec()};
1596         // This is the sign of gamma(*this). We don't use this.
1597         int sign;
1598         ::mpfr_lgamma(retval.m_value, &sign, m_value, default_rnd);
1599         return retval;
1600     }
1601     /// Exponential.
1602     /**
1603      * @return the exponential of \p this.
1604      */
exp() const1605     real exp() const
1606     {
1607         real retval{0, get_prec()};
1608         ::mpfr_exp(retval.m_value, m_value, default_rnd);
1609         return retval;
1610     }
1611     real binomial(const real &) const;
1612     /// Absolute value.
1613     /**
1614      * @return absolute value of \p this.
1615      */
abs() const1616     real abs() const
1617     {
1618         real retval(*this);
1619         ::mpfr_abs(retval.m_value, retval.m_value, default_rnd);
1620         return retval;
1621     }
1622     /// Sine.
1623     /**
1624      * @return sine of \p this, computed with the precision of \p this.
1625      */
sin() const1626     real sin() const
1627     {
1628         real retval(0, get_prec());
1629         ::mpfr_sin(retval.m_value, m_value, default_rnd);
1630         return retval;
1631     }
1632     /// Cosine.
1633     /**
1634      * @return cosine of \p this, computed with the precision of \p this.
1635      */
cos() const1636     real cos() const
1637     {
1638         real retval(0, get_prec());
1639         ::mpfr_cos(retval.m_value, m_value, default_rnd);
1640         return retval;
1641     }
1642     /// Pi constant.
1643     /**
1644      * @return pi constant calculated to the current precision of \p this.
1645      */
pi() const1646     real pi() const
1647     {
1648         real retval(0, get_prec());
1649         ::mpfr_const_pi(retval.m_value, default_rnd);
1650         return retval;
1651     }
1652     /// Overload output stream operator for piranha::real.
1653     /**
1654      * The output format for finite numbers is normalised scientific notation, where the exponent is signalled by the
1655      * letter 'e'
1656      * and suppressed if null.
1657      *
1658      * For non-finite numbers, the string representation is one of "nan", "inf" or "-inf".
1659      *
1660      * @param os output stream.
1661      * @param r piranha::real to be directed to stream.
1662      *
1663      * @return reference to \p os.
1664      *
1665      * @throws std::invalid_argument if the conversion to string via the MPFR API fails.
1666      * @throws std::overflow_error if the exponent is smaller than an implementation-defined minimum.
1667      * @throws unspecified any exception thrown by memory allocation errors in standard containers.
1668      */
operator <<(std::ostream & os,const real & r)1669     friend std::ostream &operator<<(std::ostream &os, const real &r)
1670     {
1671         if (r.is_nan()) {
1672             os << "nan";
1673             return os;
1674         }
1675         if (r.is_inf()) {
1676             if (r.sign() > 0) {
1677                 os << "inf";
1678             } else {
1679                 os << "-inf";
1680             }
1681             return os;
1682         }
1683         ::mpfr_exp_t exp(0);
1684         char *cptr = ::mpfr_get_str(nullptr, &exp, 10, 0, r.m_value, default_rnd);
1685         if (unlikely(!cptr)) {
1686             piranha_throw(std::overflow_error,
1687                           "error in conversion of real to rational: the call to the MPFR function failed");
1688         }
1689         smart_mpfr_str str(cptr, ::mpfr_free_str);
1690         // Copy into C++ string.
1691         std::string cpp_str(str.get());
1692         // Insert the radix point.
1693         auto it = std::find_if(cpp_str.begin(), cpp_str.end(), [](char c) { return detail::is_digit(c); });
1694         if (it != cpp_str.end()) {
1695             ++it;
1696             cpp_str.insert(it, '.');
1697             if (exp == std::numeric_limits<::mpfr_exp_t>::min()) {
1698                 piranha_throw(std::overflow_error, "overflow in conversion of real to string");
1699             }
1700             --exp;
1701             if (exp != ::mpfr_exp_t(0) && r.sign() != 0) {
1702                 cpp_str.append("e" + boost::lexical_cast<std::string>(exp));
1703             }
1704         }
1705         os << cpp_str;
1706         return os;
1707     }
1708     /// Overload input stream operator for piranha::real.
1709     /**
1710      * Equivalent to extracting a line from the stream and then assigning it to \p r.
1711      *
1712      * @param is input stream.
1713      * @param r real to which the contents of the stream will be assigned.
1714      *
1715      * @return reference to \p is.
1716      *
1717      * @throws unspecified any exception thrown by the assignment operator from string of piranha::real.
1718      */
operator >>(std::istream & is,real & r)1719     friend std::istream &operator>>(std::istream &is, real &r)
1720     {
1721         std::string tmp_str;
1722         std::getline(is, tmp_str);
1723         r = tmp_str;
1724         return is;
1725     }
1726     /** @name Low-level interface
1727      * Low-level methods. These methods allow direct access to the internal
1728      * MPFR instance.
1729      */
1730     //@{
1731     /// Get a mutable reference to the internal <tt>mpfr_t</tt> instance.
get_mpfr_t()1732     std::remove_extent<::mpfr_t>::type *get_mpfr_t()
1733     {
1734         return &m_value[0u];
1735     }
1736     /// Get a const reference to the internal <tt>mpfr_t</tt> instance.
get_mpfr_t() const1737     const std::remove_extent<::mpfr_t>::type *get_mpfr_t() const
1738     {
1739         return &m_value[0u];
1740     }
1741 //@}
1742 
1743 #if defined(PIRANHA_WITH_MSGPACK)
1744 private:
1745     // msgpack enabler.
1746     template <typename Stream>
1747     using msgpack_pack_enabler
1748         = enable_if_t<conjunction<is_msgpack_stream<Stream>, has_msgpack_pack<Stream, ::mpfr_prec_t>,
1749                                   has_msgpack_pack<Stream, std::string>,
1750                                   has_msgpack_pack<Stream, decltype(std::declval<const ::mpfr_t &>()->_mpfr_sign)>,
1751                                   has_msgpack_pack<Stream, decltype(std::declval<const ::mpfr_t &>()->_mpfr_exp)>,
1752                                   has_msgpack_pack<Stream, ::mp_limb_t>,
1753                                   has_safe_cast<std::uint32_t, ::mpfr_prec_t>>::value,
1754                       int>;
1755     template <typename U>
1756     using msgpack_convert_enabler
1757         = enable_if_t<conjunction<std::is_same<U, U>, // For SFINAE.
1758                                   has_msgpack_convert<::mpfr_prec_t>, has_msgpack_convert<std::string>,
1759                                   has_msgpack_convert<decltype(std::declval<const ::mpfr_t &>()->_mpfr_sign)>,
1760                                   has_msgpack_convert<decltype(std::declval<const ::mpfr_t &>()->_mpfr_exp)>,
1761                                   has_msgpack_convert<::mp_limb_t>>::value,
1762                       int>;
1763 
1764 public:
1765     /// Pack in msgpack format.
1766     /**
1767      * \note
1768      * This method is enabled only if:
1769      * - \p Stream satisfies piranha::is_msgpack_stream,
1770      * - \p std::string and the integral types in terms of which the internal representation of
1771      *   piranha::real is defined satisfy piranha::has_msgpack_pack,
1772      * - \p mpfr_prec_t can be safely converted to \p std::uint32_t.
1773      *
1774      * This method will pack \p this into \p p. If \p f is msgpack_format::portable, then
1775      * the precision of \p this and a decimal string representation of \p this are packed in an array.
1776      * Otherwise, an array of 4 elements storing the internal MPFR representation of \p this is packed.
1777      *
1778      * @param p target <tt>msgpack::packer</tt>.
1779      * @param f the desired piranha::msgpack_format.
1780      *
1781      * @throws unspecified any exception thrown by:
1782      * - piranha::safe_cast(),
1783      * - the public interface of <tt>msgpack::packer</tt>,
1784      * - piranha::msgpack_pack(),
1785      * - the conversion of \p this to string.
1786      */
1787     template <typename Stream, msgpack_pack_enabler<Stream> = 0>
msgpack_pack(msgpack::packer<Stream> & p,msgpack_format f) const1788     void msgpack_pack(msgpack::packer<Stream> &p, msgpack_format f) const
1789     {
1790         if (f == msgpack_format::portable) {
1791             std::ostringstream oss;
1792             oss << *this;
1793             auto prec = get_prec();
1794             auto s = oss.str();
1795             p.pack_array(2);
1796             piranha::msgpack_pack(p, prec, f);
1797             piranha::msgpack_pack(p, s, f);
1798         } else {
1799             // NOTE: storing both prec and the number of limbs is a bit redundant: it is possible to
1800             // infer the number of limbs from prec but not viceversa (only an upper/lower bound). So let's
1801             // store them both.
1802             p.pack_array(4);
1803             piranha::msgpack_pack(p, m_value->_mpfr_prec, f);
1804             piranha::msgpack_pack(p, m_value->_mpfr_sign, f);
1805             piranha::msgpack_pack(p, m_value->_mpfr_exp, f);
1806             const auto s = safe_cast<std::uint32_t>(size_from_prec(m_value->_mpfr_prec));
1807             p.pack_array(s);
1808             // NOTE: no need to save the size, as it can be recovered from the prec.
1809             for (std::uint32_t i = 0; i < s; ++i) {
1810                 piranha::msgpack_pack(p, m_value->_mpfr_d[i], f);
1811             }
1812         }
1813     }
1814     /// Convert from msgpack object.
1815     /**
1816      * \note
1817      * This method is enabled only if \p std::string and all the integral types used to define the internal
1818      * representation of piranha::real satisfy piranha::has_msgpack_convert.
1819      *
1820      * This method will convert the object \p o into \p this. If \p f is piranha::msgpack_format::binary,
1821      * this method offers the basic exception safety guarantee and it performs minimal checking on the input data.
1822      * Calling this method in binary mode will result in undefined behaviour if \p o does not contain an integer
1823      * serialized via msgpack_pack().
1824      *
1825      * @param o source object.
1826      * @param f the desired piranha::msgpack_format.
1827      *
1828      * @throws std::invalid_argument if, in binary mode, the number of serialized limbs is inconsistent with the
1829      * precision.
1830      * @throws unspecified any exception thrown by:
1831      * - piranha::safe_cast(),
1832      * - set_prec(),
1833      * - memory errors in standard containers,
1834      * - the public interface of <tt>msgpack::object</tt>,
1835      * - piranha::msgpack_convert(),
1836      * - the constructor of piranha::real from string.
1837      */
1838     template <typename U = real, msgpack_convert_enabler<U> = 0>
msgpack_convert(const msgpack::object & o,msgpack_format f)1839     void msgpack_convert(const msgpack::object &o, msgpack_format f)
1840     {
1841         if (f == msgpack_format::portable) {
1842             PIRANHA_MAYBE_TLS std::array<msgpack::object, 2> vobj;
1843             o.convert(vobj);
1844             ::mpfr_prec_t prec;
1845             PIRANHA_MAYBE_TLS std::string s;
1846             piranha::msgpack_convert(prec, vobj[0], f);
1847             piranha::msgpack_convert(s, vobj[1], f);
1848             *this = real(s, prec);
1849         } else {
1850             PIRANHA_MAYBE_TLS std::array<msgpack::object, 4> vobj;
1851             o.convert(vobj);
1852             // First let's handle the non-limbs members.
1853             ::mpfr_prec_t prec;
1854             decltype(m_value->_mpfr_sign) sign;
1855             decltype(m_value->_mpfr_exp) exp;
1856             piranha::msgpack_convert(prec, vobj[0], f);
1857             piranha::msgpack_convert(sign, vobj[1], f);
1858             piranha::msgpack_convert(exp, vobj[2], f);
1859             set_prec(prec);
1860             piranha_assert(m_value->_mpfr_prec == prec);
1861             m_value->_mpfr_sign = sign;
1862             m_value->_mpfr_exp = exp;
1863             // Next the limbs. Protect in try/catch so if anything goes wrong we can fix this in the
1864             // catch block before re-throwing.
1865             try {
1866                 PIRANHA_MAYBE_TLS std::vector<msgpack::object> vlimbs;
1867                 vobj[3].convert(vlimbs);
1868                 const auto s = safe_cast<std::vector<msgpack::object>::size_type>(size_from_prec(prec));
1869                 if (unlikely(s != vlimbs.size())) {
1870                     piranha_throw(std::invalid_argument,
1871                                   std::string("error in the msgpack deserialization of a real: the number "
1872                                               "of serialized limbs (")
1873                                       + std::to_string(vlimbs.size())
1874                                       + ") is not consistent with the number of limbs inferred from the precision ("
1875                                       + std::to_string(s) + ")");
1876                 }
1877                 for (decltype(vlimbs.size()) i = 0; i < s; ++i) {
1878                     piranha::msgpack_convert(m_value->_mpfr_d[i], vlimbs[i], f);
1879                 }
1880             } catch (...) {
1881                 // Set to zero before re-throwing.
1882                 ::mpfr_set_ui(m_value, 0u, default_rnd);
1883                 throw;
1884             }
1885         }
1886     }
1887 #endif
1888 
1889 private:
1890     ::mpfr_t m_value;
1891 };
1892 
1893 namespace math
1894 {
1895 
1896 /// Specialisation of the piranha::math::negate() functor for piranha::real.
1897 template <typename T>
1898 struct negate_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
1899     /// Call operator.
1900     /**
1901      * @param x piranha::real to be negated.
1902      */
operator ()piranha::math::negate_impl1903     void operator()(real &x) const
1904     {
1905         x.negate();
1906     }
1907 };
1908 
1909 /// Specialisation of the piranha::math::is_zero() functor for piranha::real.
1910 template <typename T>
1911 struct is_zero_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
1912     /// Call operator.
1913     /**
1914      * @param r piranha::real to be tested.
1915      *
1916      * @return \p true if \p r is zero, \p false otherwise.
1917      */
operator ()piranha::math::is_zero_impl1918     bool operator()(const T &r) const
1919     {
1920         return r.is_zero();
1921     }
1922 };
1923 }
1924 
1925 namespace detail
1926 {
1927 
1928 // Enabler for real pow.
1929 template <typename T, typename U>
1930 using real_pow_enabler =
1931     typename std::enable_if<(std::is_same<real, T>::value && is_real_interoperable_type<U>::value)
1932                             || (std::is_same<real, U>::value && is_real_interoperable_type<T>::value)
1933                             || (std::is_same<real, T>::value && std::is_same<real, U>::value)>::type;
1934 
1935 // Binomial follows the same rules as pow.
1936 template <typename T, typename U>
1937 using real_binomial_enabler = real_pow_enabler<T, U>;
1938 }
1939 
1940 namespace math
1941 {
1942 
1943 /// Specialisation of the piranha::math::pow() functor for piranha::real.
1944 /**
1945  * This specialisation is activated when one of the arguments is piranha::real
1946  * and the other is either piranha::real or an interoperable type for piranha::real.
1947  *
1948  * The implementation follows these rules:
1949  * - if base and exponent are both piranha::real, then piranha::real::pow() is used;
1950  * - otherwise, the non-real argument is converted to piranha::real and then piranha::real::pow()
1951  *   is used.
1952  */
1953 template <typename T, typename U>
1954 struct pow_impl<T, U, detail::real_pow_enabler<T, U>> {
1955     /// Call operator, real--real overload.
1956     /**
1957      * @param r base.
1958      * @param x exponent.
1959      *
1960      * @return \p r to the power of \p x.
1961      *
1962      * @throws unspecified any exception thrown by piranha::real::pow().
1963      */
operator ()piranha::math::pow_impl1964     real operator()(const real &r, const real &x) const
1965     {
1966         return r.pow(x);
1967     }
1968     /// Call operator, real base overload.
1969     /**
1970      * @param r base.
1971      * @param x exponent.
1972      *
1973      * @return \p r to the power of \p x.
1974      *
1975      * @throws unspecified any exception thrown by piranha::real::pow() or by
1976      * the invoked piranha::real constructor.
1977      */
1978     template <typename T2>
operator ()piranha::math::pow_impl1979     real operator()(const real &r, const T2 &x) const
1980     {
1981         // NOTE: init with the same precision as r in order
1982         // to maintain the same precision in the result.
1983         return r.pow(real{x, r.get_prec()});
1984     }
1985     /// Call operator, real exponent overload.
1986     /**
1987      * @param r base.
1988      * @param x exponent.
1989      *
1990      * @return \p r to the power of \p x.
1991      *
1992      * @throws unspecified any exception thrown by piranha::real::pow() or by
1993      * the invoked piranha::real constructor.
1994      */
1995     template <typename T2>
operator ()piranha::math::pow_impl1996     real operator()(const T2 &r, const real &x) const
1997     {
1998         return real{r, x.get_prec()}.pow(x);
1999     }
2000 };
2001 
2002 /// Specialisation of the piranha::math::sin() functor for piranha::real.
2003 template <typename T>
2004 struct sin_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2005     /// Call operator.
2006     /**
2007      * The operation will return the output of piranha::real::sin().
2008      *
2009      * @param r argument.
2010      *
2011      * @return sine of \p r.
2012      */
operator ()piranha::math::sin_impl2013     real operator()(const T &r) const
2014     {
2015         return r.sin();
2016     }
2017 };
2018 
2019 /// Specialisation of the piranha::math::cos() functor for piranha::real.
2020 template <typename T>
2021 struct cos_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2022     /// Call operator.
2023     /**
2024      * The operation will return the output of piranha::real::cos().
2025      *
2026      * @param r argument.
2027      *
2028      * @return cosine of \p r.
2029      */
operator ()piranha::math::cos_impl2030     real operator()(const T &r) const
2031     {
2032         return r.cos();
2033     }
2034 };
2035 
2036 /// Specialisation of the piranha::math::abs() functor for piranha::real.
2037 template <typename T>
2038 struct abs_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2039     /// Call operator.
2040     /**
2041      * @param x input parameter.
2042      *
2043      * @return absolute value of \p x.
2044      */
operator ()piranha::math::abs_impl2045     T operator()(const T &x) const
2046     {
2047         return x.abs();
2048     }
2049 };
2050 
2051 /// Specialisation of the piranha::math::partial() functor for piranha::real.
2052 template <typename T>
2053 struct partial_impl<T, typename std::enable_if<std::is_same<T, real>::value>::type> {
2054     /// Call operator.
2055     /**
2056      * @return an instance of piranha::real constructed from zero.
2057      */
operator ()piranha::math::partial_impl2058     real operator()(const real &, const std::string &) const
2059     {
2060         return real(0);
2061     }
2062 };
2063 
2064 /// Specialisation of the piranha::math::binomial() functor for piranha::real.
2065 /**
2066  * This specialisation is activated when one of the arguments is piranha::real
2067  * and the other is either piranha::real or an interoperable type for piranha::real.
2068  *
2069  * The implementation follows these rules:
2070  * - if top and bottom are both piranha::real, then piranha::real::binomial() is used;
2071  * - otherwise, the non-real argument is converted to piranha::real and then piranha::real::binomial()
2072  *   is used.
2073  */
2074 template <typename T, typename U>
2075 struct binomial_impl<T, U, detail::real_binomial_enabler<T, U>> {
2076     /// Call operator, real--real overload.
2077     /**
2078      * @param x top.
2079      * @param y bottom.
2080      *
2081      * @return \p x choose \p y.
2082      *
2083      * @throws unspecified any exception thrown by piranha::real::binomial().
2084      */
operator ()piranha::math::binomial_impl2085     real operator()(const real &x, const real &y) const
2086     {
2087         return x.binomial(y);
2088     }
2089     /// Call operator, real top overload.
2090     /**
2091      * @param x top.
2092      * @param y bottom.
2093      *
2094      * @return \p x choose \p y.
2095      *
2096      * @throws unspecified any exception thrown by piranha::real::binomial() or by the invoked
2097      * piranha::real constructor.
2098      */
2099     template <typename T2>
operator ()piranha::math::binomial_impl2100     real operator()(const real &x, const T2 &y) const
2101     {
2102         // NOTE: init with the same precision as r in order
2103         // to maintain the same precision in the result.
2104         return x.binomial(real{y, x.get_prec()});
2105     }
2106     /// Call operator, real bottom overload.
2107     /**
2108      * @param x top.
2109      * @param y bottom.
2110      *
2111      * @return \p x choose \p y.
2112      *
2113      * @throws unspecified any exception thrown by piranha::real::binomial() or by the invoked
2114      * piranha::real constructor.
2115      */
2116     template <typename T2>
operator ()piranha::math::binomial_impl2117     real operator()(const T2 &x, const real &y) const
2118     {
2119         return real{x, y.get_prec()}.binomial(y);
2120     }
2121 };
2122 
2123 /// Specialisation of the implementation of piranha::math::multiply_accumulate() for piranha::real.
2124 template <>
2125 struct multiply_accumulate_impl<real> {
2126     /// Call operator.
2127     /**
2128      * This implementation will use piranha::real::multiply_accumulate().
2129      *
2130      * @param x target value for accumulation.
2131      * @param y first argument.
2132      * @param z second argument.
2133      */
operator ()piranha::math::multiply_accumulate_impl2134     void operator()(real &x, const real &y, const real &z) const
2135     {
2136         x.multiply_accumulate(y, z);
2137     }
2138 };
2139 }
2140 
~real()2141 inline real::~real()
2142 {
2143     PIRANHA_TT_CHECK(is_cf, real);
2144     static_assert(default_prec >= MPFR_PREC_MIN && default_prec <= MPFR_PREC_MAX,
2145                   "Invalid value for default precision.");
2146     if (m_value->_mpfr_d) {
2147         ::mpfr_clear(m_value);
2148     } else {
2149 // NOTE: the story here is that ICC has a weird behaviour when the thread_local
2150 // storage. Essentially, the thread-local static variable in the fma() function
2151 // upon destruction has the _mpfr_d set to zero for some reason but the other members
2152 // are not zeroed out. This results in the asserts below firing, and probably a memory
2153 // leak as well as the variable is not cleared. We just disable the asserts for now.
2154 #if !defined(PIRANHA_COMPILER_IS_INTEL)
2155         piranha_assert(!m_value->_mpfr_prec);
2156         piranha_assert(!m_value->_mpfr_sign);
2157         piranha_assert(!m_value->_mpfr_exp);
2158 #endif
2159     }
2160 }
2161 
2162 namespace detail
2163 {
2164 
2165 // Compute gamma(a)/(gamma(b) * gamma(c)), assuming a, b and c are not negative ints. The logarithm
2166 // of the gamma function is used internally.
real_compute_3_gamma(const real & a,const real & b,const real & c,const::mpfr_prec_t & prec)2167 inline real real_compute_3_gamma(const real &a, const real &b, const real &c, const ::mpfr_prec_t &prec)
2168 {
2169     // Here we should never enter with negative ints.
2170     piranha_assert(a.sign() >= 0 || a.truncated() != a);
2171     piranha_assert(b.sign() >= 0 || b.truncated() != b);
2172     piranha_assert(c.sign() >= 0 || c.truncated() != c);
2173     const real pi = real{0, prec}.pi();
2174     real tmp0(0), tmp1(1);
2175     if (a.sign() < 0) {
2176         tmp0 -= (1 - a).lgamma();
2177         tmp1 *= pi / (a * pi).sin();
2178     } else {
2179         tmp0 += a.lgamma();
2180     }
2181     if (b.sign() < 0) {
2182         tmp0 += (1 - b).lgamma();
2183         tmp1 *= (b * pi).sin() / pi;
2184     } else {
2185         tmp0 -= b.lgamma();
2186     }
2187     if (c.sign() < 0) {
2188         tmp0 += (1 - c).lgamma();
2189         tmp1 *= (c * pi).sin() / pi;
2190     } else {
2191         tmp0 -= c.lgamma();
2192     }
2193     return tmp0.exp() * tmp1;
2194 }
2195 }
2196 
2197 /// Binomial coefficient.
2198 /**
2199  * This method will return \p this choose \p y. Any combination of real values is supported.
2200  * The implementation uses the logarithm of the gamma function, thus the result will not be in
2201  * general exact (even if \p this and \p y are integral values).
2202  *
2203  * The returned value will have the maximum precision between \p this and \p y.
2204  *
2205  * @param y bottom value.
2206  *
2207  * @return \p this choose \p y.
2208  *
2209  * @throws std::invalid_argument if either \p this or \p y is not finite.
2210  * @throws unspecified any exception resulting from arithmetic operations on piranha::real.
2211  */
binomial(const real & y) const2212 inline real real::binomial(const real &y) const
2213 {
2214     if (unlikely(is_nan() || is_inf() || y.is_nan() || y.is_inf())) {
2215         piranha_throw(std::invalid_argument, "cannot compute binomial coefficient with non-finite real argument(s)");
2216     }
2217     // Work with the max precision.
2218     const ::mpfr_prec_t max_prec = std::max<::mpfr_prec_t>(get_prec(), y.get_prec());
2219     const bool neg_int_x = truncated() == (*this) && sign() < 0, neg_int_y = y.truncated() == y && y.sign() < 0,
2220                neg_int_x_y = ((*this) - y).truncated() == ((*this) - y) && ((*this) - y).sign() < 0;
2221     const unsigned mask = unsigned(neg_int_x) + (unsigned(neg_int_y) << 1u) + (unsigned(neg_int_x_y) << 2u);
2222     switch (mask) {
2223         case 0u:
2224             // Case 0 is the non-special one, use the default implementation.
2225             return detail::real_compute_3_gamma((*this) + 1, y + 1, (*this) - y + 1, max_prec);
2226         // NOTE: case 1 is not possible: x < 0, y > 0 implies x - y < 0 always.
2227         case 2u:
2228         case 4u:
2229             // These are finite numerators with infinite denominators.
2230             return real{0, max_prec};
2231         // NOTE: case 6 is not possible: x > 0, y < 0 implies x - y > 0 always.
2232         case 3u: {
2233             // 3 and 5 are the cases with 1 inf in num and 1 inf in den. Use the transformation
2234             // formula to make them finite.
2235             // NOTE: the phase here is really just a sign, but it seems tricky to compute this exactly
2236             // due to potential rounding errors. We are attempting to err on the safe side by using pow()
2237             // here.
2238             const auto phase = math::pow(-1, (*this) + 1) / math::pow(-1, y + 1);
2239             return detail::real_compute_3_gamma(-y, -(*this), (*this) - y + 1, max_prec) * phase;
2240         }
2241         case 5u: {
2242             const auto phase = math::pow(-1, (*this) - y + 1) / math::pow(-1, (*this) + 1);
2243             return detail::real_compute_3_gamma(-((*this) - y), y + 1, -(*this), max_prec) * phase;
2244         }
2245     }
2246     // Case 7 returns zero -> from inf / (inf * inf) it becomes a / (b * inf) after the transform.
2247     // NOTE: put it here so the compiler does not complain about missing return statement in the switch block.
2248     return real{0, max_prec};
2249 }
2250 
2251 inline namespace impl
2252 {
2253 
2254 template <typename To, typename From>
2255 using sc_real_enabler
2256     = enable_if_t<conjunction<disjunction<std::is_integral<To>, detail::is_mp_integer<To>, detail::is_mp_rational<To>>,
2257                               std::is_same<From, real>>::value>;
2258 }
2259 
2260 /// Specialisation of piranha::safe_cast() for conversions involving piranha::real.
2261 /**
2262  * \note
2263  * This specialisation is enabled if \p To is an integral type, piranha::mp_integer or piranha::mp_rational, and \p From
2264  * is piranha::real.
2265  */
2266 template <typename To, typename From>
2267 struct safe_cast_impl<To, From, sc_real_enabler<To, From>> {
2268 private:
2269     template <typename T>
2270     using integral_enabler = enable_if_t<disjunction<std::is_integral<T>, detail::is_mp_integer<T>>::value, int>;
2271     template <typename T>
2272     using rational_enabler = enable_if_t<detail::is_mp_rational<T>::value, int>;
2273 
2274 public:
2275     /// Call operator, real to integral overload.
2276     /**
2277      * \note
2278      * This operator is enabled if \p To is an integral type or an instance of piranha::mp_integer.
2279      *
2280      * The conversion will succeed if \p r is a finite integral value representable by
2281      * the target type.
2282      *
2283      * @param r conversion argument.
2284      *
2285      * @return \p r converted to \p To.
2286      *
2287      * @throws piranha::safe_cast_failure if the conversion fails.
2288      * @throws unspecified any exception thrown by \p boost::lexical_cast().
2289      */
2290     template <typename T = To, integral_enabler<T> = 0>
2291     T operator()(const real &r) const
2292     {
2293         // NOTE: the finiteness check here is repeated in the cast below, but we need it here in order
2294         // to make sure that we can compute the truncated r.
2295         if (unlikely(r.is_inf() || r.is_nan() || r.truncated() != r)) {
2296             piranha_throw(safe_cast_failure, "cannot convert the input real " + boost::lexical_cast<std::string>(r)
2297                                                  + " to the integral type '" + detail::demangle<To>()
2298                                                  + "', as the input real does not represent a finite integral value");
2299         }
2300         try {
2301             return static_cast<T>(r);
2302         } catch (const std::overflow_error &) {
2303             piranha_throw(safe_cast_failure, "cannot convert the input real " + boost::lexical_cast<std::string>(r)
2304                                                  + " to the integral type '" + detail::demangle<To>()
2305                                                  + "', as the conversion would not preserve the value");
2306         }
2307     }
2308     /// Call operator, real to rational overload.
2309     /**
2310      * \note
2311      * This operator is enabled if \p To is an instance of piranha::mp_rational.
2312      *
2313      * @param r conversion argument.
2314      *
2315      * @return \p r converted to piranha::mp_rational.
2316      *
2317      * @throws piranha::safe_cast_failure if the conversion fails.
2318      * @throws unspecified any exception thrown by \p boost::lexical_cast().
2319      */
2320     template <typename T = To, rational_enabler<T> = 0>
2321     T operator()(const real &r) const
2322     {
2323         try {
2324             return static_cast<T>(r);
2325         } catch (const std::overflow_error &) {
2326             piranha_throw(safe_cast_failure, "cannot convert the input real " + boost::lexical_cast<std::string>(r)
2327                                                  + " to the rational type '" + detail::demangle<To>()
2328                                                  + "', as the conversion would not preserve the value");
2329         }
2330     }
2331 };
2332 
2333 inline namespace literals
2334 {
2335 
2336 /// Literal for piranha::real.
2337 /**
2338  * The return value will be constructed with default precision.
2339  *
2340  * @param s literal string.
2341  *
2342  * @return a piranha::real constructed from \p s.
2343  *
2344  * @throws unspecified any exception thrown by the constructor of
2345  * piranha::real from string.
2346  */
operator ""_r(const char * s)2347 inline real operator"" _r(const char *s)
2348 {
2349     return real(s);
2350 }
2351 }
2352 
2353 inline namespace impl
2354 {
2355 
2356 template <typename Archive>
2357 using real_boost_save_enabler
2358     = enable_if_t<conjunction<has_boost_save<Archive, ::mpfr_prec_t>, has_boost_save<Archive, std::string>,
2359                               has_boost_save<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_sign)>,
2360                               has_boost_save<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_exp)>,
2361                               has_boost_save<Archive, ::mp_limb_t>>::value>;
2362 
2363 template <typename Archive>
2364 using real_boost_load_enabler
2365     = enable_if_t<conjunction<has_boost_load<Archive, ::mpfr_prec_t>, has_boost_load<Archive, std::string>,
2366                               has_boost_load<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_sign)>,
2367                               has_boost_load<Archive, decltype(std::declval<const ::mpfr_t &>()->_mpfr_exp)>,
2368                               has_boost_load<Archive, ::mp_limb_t>>::value>;
2369 }
2370 
2371 /// Specialisation of piranha::boost_save() for piranha::real.
2372 /**
2373  * \note
2374  * This specialisation is enabled only if \p std::string and all the integral types in terms of which piranha::real
2375  * is implemented satisfy piranha::has_boost_save.
2376  *
2377  * If \p Archive is \p boost::archive::binary_oarchive, a platform dependent binary representation of the input
2378  * piranha::real will be saved. Otherwise, the piranha::real is serialized in string form.
2379  *
2380  * @throws unspecified any exception thrown by piranha::boost_save() or by the conversion of the input piranha::real to
2381  * string.
2382  */
2383 template <typename Archive>
2384 struct boost_save_impl<Archive, real, real_boost_save_enabler<Archive>> : boost_save_via_boost_api<Archive, real> {
2385 };
2386 
2387 /// Specialisation of piranha::boost_load() for piranha::real.
2388 /**
2389  * \note
2390  * This specialisation is enabled only if \p std::string and all the integral types in terms of which piranha::real
2391  * is implemented satisfy piranha::has_boost_load.
2392  *
2393  * If \p Archive is \p boost::archive::binary_iarchive, no checking is performed on the deserialized piranha::real
2394  * and the implementation offers the basic exception safety guarantee.
2395  *
2396  * @throws unspecified any exception thrown by piranha::boost_load(), or by the constructor of
2397  * piranha::real from string.
2398  */
2399 template <typename Archive>
2400 struct boost_load_impl<Archive, real, real_boost_load_enabler<Archive>> : boost_load_via_boost_api<Archive, real> {
2401 };
2402 
2403 #if defined(PIRANHA_WITH_MSGPACK)
2404 
2405 inline namespace impl
2406 {
2407 
2408 // Enablers for msgpack serialization.
2409 template <typename Stream>
2410 using real_msgpack_pack_enabler = enable_if_t<is_detected<msgpack_pack_member_t, Stream, real>::value>;
2411 
2412 template <typename T>
2413 using real_msgpack_convert_enabler
2414     = enable_if_t<conjunction<std::is_same<real, T>, is_detected<msgpack_convert_member_t, T>>::value>;
2415 }
2416 
2417 /// Specialisation of piranha::msgpack_pack() for piranha::real.
2418 /**
2419  * \note
2420  * This specialisation is enabled if \p T is piranha::real and
2421  * the piranha::real::msgpack_pack() method is supported with a stream of type \p Stream.
2422  */
2423 template <typename Stream>
2424 struct msgpack_pack_impl<Stream, real, real_msgpack_pack_enabler<Stream>> {
2425     /// Call operator.
2426     /**
2427      * The call operator will use piranha::real::msgpack_pack() internally.
2428      *
2429      * @param p target <tt>msgpack::packer</tt>.
2430      * @param x piranha::real to be serialized.
2431      * @param f the desired piranha::msgpack_format.
2432      *
2433      * @throws unspecified any exception thrown by piranha::real::msgpack_pack().
2434      */
operator ()piranha::msgpack_pack_impl2435     void operator()(msgpack::packer<Stream> &p, const real &x, msgpack_format f) const
2436     {
2437         x.msgpack_pack(p, f);
2438     }
2439 };
2440 
2441 /// Specialisation of piranha::msgpack_convert() for piranha::real.
2442 /**
2443  * \note
2444  * This specialisation is enabled if \p T is piranha::real and
2445  * the piranha::real::msgpack_convert() method is supported.
2446  */
2447 template <typename T>
2448 struct msgpack_convert_impl<T, real_msgpack_convert_enabler<T>> {
2449     /// Call operator.
2450     /**
2451      * The call operator will use piranha::real::msgpack_convert() internally.
2452      *
2453      * @param x target piranha::real.
2454      * @param o the <tt>msgpack::object</tt> to be converted into \p n.
2455      * @param f the desired piranha::msgpack_format.
2456      *
2457      * @throws unspecified any exception thrown by piranha::real::msgpack_convert().
2458      */
operator ()piranha::msgpack_convert_impl2459     void operator()(T &x, const msgpack::object &o, msgpack_format f) const
2460     {
2461         x.msgpack_convert(o, f);
2462     }
2463 };
2464 
2465 #endif
2466 
2467 inline namespace impl
2468 {
2469 
2470 template <typename T>
2471 using real_zero_is_absorbing_enabler = enable_if_t<std::is_same<uncvref_t<T>, real>::value>;
2472 }
2473 
2474 /// Specialisation of piranha::zero_is_absorbing for piranha::real.
2475 /**
2476  * \note
2477  * This specialisation is enabled if \p T, after the removal of cv/reference qualifiers, is piranha::real.
2478  *
2479  * Due to the presence of NaN, the zero element is not absorbing for piranha::real.
2480  */
2481 template <typename T>
2482 struct zero_is_absorbing<T, real_zero_is_absorbing_enabler<T>> {
2483     /// Value of the type trait.
2484     static const bool value = false;
2485 };
2486 
2487 template <typename T>
2488 const bool zero_is_absorbing<T, real_zero_is_absorbing_enabler<T>>::value;
2489 }
2490 
2491 #endif
2492