cd3a010fdb
[CI SKIP]
6199 lines
338 KiB
Plaintext
6199 lines
338 KiB
Plaintext
[/
|
|
Copyright 2011, 2013 John Maddock.
|
|
Copyright 2013 - 2019 Paul A. Bristow.
|
|
Copyright 2013 Christopher Kormanyos.
|
|
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt).
|
|
]
|
|
|
|
[library Boost.Multiprecision
|
|
[quickbook 1.7]
|
|
[copyright 2002-2019 John Maddock and Christopher Kormanyos]
|
|
[purpose Multiprecision Number library]
|
|
[license
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
[@http://www.boost.org/LICENSE_1_0.txt])
|
|
]
|
|
[authors [Maddock, John], [Kormanyos, Christopher]]
|
|
[/last-revision $Date: 2011-07-08 18:51:46 +0100 (Fri, 08 Jul 2011) $]
|
|
]
|
|
|
|
[import html4_symbols.qbk] [/Ideally this should be the same as Boost.Math I:\boost\libs\math\doc]
|
|
|
|
[import ../example/gmp_snips.cpp]
|
|
[import ../example/mpfr_snips.cpp]
|
|
[import ../example/mpfi_snips.cpp]
|
|
[import ../example/float128_snips.cpp]
|
|
[import ../example/cpp_dec_float_snips.cpp]
|
|
[import ../example/cpp_bin_float_snips.cpp]
|
|
[import ../example/cpp_int_import_export.cpp]
|
|
[import ../example/cpp_bin_float_import_export.cpp]
|
|
[import ../example/tommath_snips.cpp]
|
|
[import ../example/cpp_int_snips.cpp]
|
|
[import ../example/random_snips.cpp]
|
|
[import ../example/safe_prime.cpp]
|
|
[import ../example/mixed_integer_arithmetic.cpp]
|
|
[import ../example/logged_adaptor.cpp]
|
|
[import ../example/numeric_limits_snips.cpp]
|
|
[import ../example/hashing_examples.cpp]
|
|
[import ../example/cpp_complex_examples.cpp]
|
|
[import ../example/mpc_examples.cpp]
|
|
[import ../example/complex128_examples.cpp]
|
|
[import ../example/eigen_example.cpp]
|
|
[import ../example/mpfr_precision.cpp]
|
|
[import ../example/constexpr_float_arithmetic_examples.cpp]
|
|
[import ../test/constexpr_test_cpp_int_5.cpp]
|
|
|
|
[/External links as templates (see also some defs below)]
|
|
[template mpfr[] [@http://www.mpfr.org MPFR]]
|
|
[template mpc[] [@http://www.multiprecision.org MPC]]
|
|
[template mpfi[] [@http://perso.ens-lyon.fr/nathalie.revol/software.html MPFI]]
|
|
[template gmp[] [@http://gmplib.org GMP]]
|
|
[template mpf_class[] [@http://gmplib.org/manual/C_002b_002b-Interface-Floats.html#C_002b_002b-Interface-Floats mpf_class]]
|
|
[template mpfr_class[] [@http://math.berkeley.edu/~wilken/code/gmpfrxx/ mpfr_class]]
|
|
[template mpreal[] [@http://www.holoborodko.com/pavel/mpfr/ mpreal]]
|
|
[template mpir[] [@http://mpir.org/ MPIR]]
|
|
[template tommath[] [@http://libtom.net libtommath]]
|
|
[template quadmath[] [@http://gcc.gnu.org/onlinedocs/libquadmath/ libquadmath]]
|
|
|
|
[template super[x]'''<superscript>'''[x]'''</superscript>''']
|
|
[template sub[x]'''<subscript>'''[x]'''</subscript>''']
|
|
|
|
|
|
[/insert Equation as a PNG or SVG image, previous generated with an external tool like Latex.]
|
|
[/Used thus [equation ellint6] - without the file type suffix which will chosen automatically.]
|
|
|
|
[template equation[name] '''<inlinemediaobject>
|
|
<imageobject role="html">
|
|
<imagedata fileref="../'''[name]'''.png"></imagedata>
|
|
</imageobject>
|
|
<imageobject role="print">
|
|
<imagedata fileref="../'''[name]'''.svg"></imagedata>
|
|
</imageobject>
|
|
</inlinemediaobject>''']
|
|
|
|
[/insert Indented one-line expression italic and serif font probably using Unicode symbols for Greek and symbols.]
|
|
[/Example: [expression [sub 1]F[sub 0](a, z) = (1-z)[super -a]]]
|
|
[template expression[equation]
|
|
[:
|
|
[role serif_italic [equation]]
|
|
]
|
|
[/ Hint you may need to enclose equation in brackets if it contains comma(s) to avoid "error invalid number of arguments"]
|
|
]
|
|
|
|
[def __tick [role aligncenter [role green \u2714]]] [/ u2714 is a HEAVY CHECK MARK tick (2713 check mark), green]
|
|
[def __cross [role aligncenter [role red \u2718]]] [/ u2718 is a heavy cross, red]
|
|
[def __star [role aligncenter [role red \u2736]]] [/ 6-point star red ]
|
|
|
|
[/Boost.Multiprecision internals links]
|
|
[def __cpp_int [link boost_multiprecision.tut.ints.cpp_int cpp_int]]
|
|
[def __gmp_int [link boost_multiprecision.tut.ints.gmp_int gmp_int]]
|
|
[def __tom_int [link boost_multiprecision.tut.ints.tom_int tom_int]]
|
|
[def __gmp_float [link boost_multiprecision.tut.floats.gmp_float gmp_float]]
|
|
[def __mpf_float [link boost_multiprecision.tut.floats.gmp_float gmp_float]]
|
|
[def __mpfr_float_backend [link boost_multiprecision.tut.floats.mpfr_float mpfr_float]]
|
|
[def __cpp_bin_float [link boost_multiprecision.tut.floats.cpp_bin_float cpp_bin_float]]
|
|
[def __cpp_dec_float [link boost_multiprecision.tut.floats.cpp_dec_float cpp_dec_float]]
|
|
[def __gmp_rational [link boost_multiprecision.tut.rational.gmp_rational gmp_rational]]
|
|
[def __cpp_rational [link boost_multiprecision.tut.rational.cpp_rational cpp_rational]]
|
|
[def __tommath_rational [link boost_multiprecision.tut.rational.tommath_rational tommath_rational]]
|
|
[def __number [link boost_multiprecision.ref.number number]]
|
|
[def __float128 [link boost_multiprecision.tut.floats.float128 float128]]
|
|
[def __cpp_complex [link boost_multiprecision.tut.complex.cpp_complex cpp_complex]]
|
|
[def __mpc_complex [link boost_multiprecision.tut.complex.mpc_complex mpc_complex]]
|
|
[def __debug_adaptor [link boost_multiprecision.tut.misc.debug_adaptor debug_adaptor]]
|
|
[def __logged_adaptor [link boost_multiprecision.tut.misc.logged_adaptor logged_adaptor]]
|
|
[def __rational_adaptor [link boost_multiprecision.tut.rational.rational_adaptor rational_adaptor]]
|
|
[def __cpp_complex [link boost_multiprecision.tut.complex.cpp_complex cpp_complex]]
|
|
[def __mpc_complex [link boost_multiprecision.tut.complex.mpc_complex mpc_complex]]
|
|
[def __complex128 [link boost_multiprecision.tut.complex.complex128 complex128]]
|
|
[def __complex_adaptor [link boost_multiprecision.tut.complex.complex_adaptor complex_adaptor]]
|
|
|
|
[/External links as macro definitions.]
|
|
[def __expression_template [@https://en.wikipedia.org/wiki/Expression_templates expression template]]
|
|
[def __expression_templates [@https://en.wikipedia.org/wiki/Expression_templates expression templates]] [/plural version]
|
|
[def __UDT [@http://eel.is/c++draft/definitions#defns.prog.def.type program-defined type]]
|
|
[def __fundamental_type [@https://en.cppreference.com/w/cpp/language/types fundamental (built-in) type]]
|
|
|
|
[section:intro Introduction]
|
|
|
|
The Multiprecision Library provides [link boost_multiprecision.tut.ints integer],
|
|
[link boost_multiprecision.tut.rational rational],
|
|
[link boost_multiprecision.tut.floats floating-point],
|
|
and [link boost_multiprecision.tut.complex complex] types in C++ that have more
|
|
range and precision than C++'s ordinary built-in types.
|
|
The big number types in Multiprecision can be used with a wide
|
|
selection of basic mathematical operations, elementary transcendental
|
|
functions as well as the functions in Boost.Math.
|
|
The Multiprecision types can also interoperate with any
|
|
__fundamental_type in C++ using clearly defined conversion rules.
|
|
This allows Boost.Multiprecision to be used for all
|
|
kinds of mathematical calculations involving integer,
|
|
rational and floating-point types requiring extended
|
|
range and precision.
|
|
|
|
Multiprecision consists of a generic interface to the
|
|
mathematics of large numbers as well as a selection of
|
|
big number back-ends, with support for integer, rational,
|
|
floating-point, and complex types. Boost.Multiprecision provides a selection
|
|
of back-ends provided off-the-rack in including
|
|
interfaces to GMP, MPFR, MPIR, MPC, TomMath as well as
|
|
its own collection of Boost-licensed, header-only back-ends for
|
|
integers, rationals and floats. In addition, user-defined back-ends
|
|
can be created and used with the interface of Multiprecision,
|
|
provided the class implementation adheres to the necessary
|
|
[link boost_multiprecision.ref.backendconc concepts].
|
|
|
|
Depending upon the number type, precision may be arbitrarily large
|
|
(limited only by available memory), fixed at compile time
|
|
(for example, 50 or 100 decimal digits), or a variable controlled at run-time
|
|
by member functions. The types are __expression_templates - enabled for
|
|
better performance than naive user-defined types.
|
|
|
|
The Multiprecision library comes in two distinct parts:
|
|
|
|
* An expression-template-enabled front-end `number`
|
|
that handles all the operator overloading, expression evaluation optimization, and code reduction.
|
|
* A selection of back-ends that implement the actual arithmetic operations, and need conform only to the
|
|
reduced interface requirements of the front-end.
|
|
|
|
Separation of front-end and back-end allows use of highly refined, but restricted license libraries
|
|
where possible, but provides Boost license alternatives for users who must have a portable
|
|
unconstrained license.
|
|
Which is to say some back-ends rely on 3rd party libraries,
|
|
but a header-only Boost license version is always available (if somewhat slower).
|
|
|
|
[h5:getting_started Getting started with Boost.Multiprecision]
|
|
|
|
Should you just wish to 'cut to the chase' just to get bigger integers and/or bigger and more precise reals as simply and portably as possible,
|
|
close to 'drop-in' replacements for the __fundamental_type analogs,
|
|
then use a fully Boost-licensed number type, and skip to one of more of :
|
|
|
|
* __cpp_int for multiprecision integers,
|
|
* __cpp_rational for rational types,
|
|
* __cpp_bin_float and __cpp_dec_float for multiprecision floating-point types,
|
|
* __cpp_complex for complex types.
|
|
|
|
The library is very often used via one of the predefined convenience `typedef`s
|
|
like `boost::multiprecision::int128_t` or `boost::multiprecision::cpp_bin_float_quad`.
|
|
|
|
For example, if you want a signed, 128-bit fixed size integer:
|
|
|
|
#include <boost/multiprecision/cpp_int.hpp> // Integer types.
|
|
|
|
boost::multiprecision::int128_t my_128_bit_int;
|
|
|
|
Alternatively, and more adventurously, if you wanted an
|
|
[@http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic arbitrary precision]
|
|
integer type using [gmp] as the underlying implementation then you could use:
|
|
|
|
#include <boost/multiprecision/gmp.hpp> // Defines the wrappers around the GMP library's types
|
|
|
|
boost::multiprecision::mpz_int myint; // Arbitrary precision integer type.
|
|
|
|
Or for a simple, portable 128-bit floating-point close to a drop-in for a __fundamental_type like `double`, usually 64-bit
|
|
|
|
#include <boost/multiprecision/cpp_bin_float.hpp>
|
|
|
|
boost::multiprecision::cpp_bin_float_quad my_quad_real;
|
|
|
|
Alternatively, you can compose your own 'custom' multiprecision type, by combining `number` with one of the
|
|
predefined back-end types. For example, suppose you wanted a 300 decimal digit floating-point type
|
|
based on the [mpfr] library. In this case, there's no predefined `typedef` with that level of precision,
|
|
so instead we compose our own:
|
|
|
|
#include <boost/multiprecision/mpfr.hpp> // Defines the Backend type that wraps MPFR.
|
|
|
|
namespace mp = boost::multiprecision; // Reduce the typing a bit later...
|
|
|
|
typedef mp::number<mp::mpfr_float_backend<300> > my_float;
|
|
|
|
my_float a, b, c; // These variables have 300 decimal digits precision.
|
|
|
|
We can repeat the above example, but with the expression templates disabled (for faster compile times, but slower runtimes)
|
|
by passing a second template argument to `number`:
|
|
|
|
#include <boost/multiprecision/mpfr.hpp> // Defines the Backend type that wraps MPFR.
|
|
|
|
namespace mp = boost::multiprecision; // Reduce the typing a bit later...
|
|
|
|
typedef mp::number<mp::mpfr_float_backend<300>, et_off> my_float;
|
|
|
|
my_float a, b, c; // These variables have 300 decimal digits precision
|
|
|
|
We can also mix arithmetic operations between different types, provided there is an unambiguous implicit conversion from one
|
|
type to the other:
|
|
|
|
#include <boost/multiprecision/cpp_int.hpp>
|
|
|
|
namespace mp = boost::multiprecision; // Reduce the typing a bit later...
|
|
|
|
mp::int128_t a(3), b(4);
|
|
mp::int512_t c(50), d;
|
|
|
|
d = c * a; // OK, result of mixed arithmetic is an int512_t
|
|
|
|
Conversions are also allowed:
|
|
|
|
d = a; // OK, widening conversion.
|
|
d = a * b; // OK, can convert from an expression template too.
|
|
|
|
However conversions that are inherently lossy are either declared explicit or else forbidden altogether:
|
|
|
|
d = 3.14; // Error implicit conversion from double not allowed.
|
|
d = static_cast<mp::int512_t>(3.14); // OK explicit construction is allowed
|
|
|
|
Mixed arithmetic will fail if the conversion is either ambiguous or explicit:
|
|
|
|
number<cpp_int_backend<>, et_off> a(2);
|
|
number<cpp_int_backend<>, et_on> b(3);
|
|
|
|
b = a * b; // Error, implicit conversion could go either way.
|
|
b = a * 3.14; // Error, no operator overload if the conversion would be explicit.
|
|
|
|
[h4 Move Semantics]
|
|
|
|
On compilers that support rvalue-references, class `number` is move-enabled if the underlying backend is.
|
|
|
|
In addition the non-expression template operator overloads (see below) are move aware and have overloads
|
|
that look something like:
|
|
|
|
template <class B>
|
|
number<B, et_off> operator + (number<B, et_off>&& a, const number<B, et_off>& b)
|
|
{
|
|
return std::move(a += b);
|
|
}
|
|
|
|
These operator overloads ensure that many expressions can be evaluated without actually generating any temporaries.
|
|
However, there are still many simple expressions such as
|
|
|
|
a = b * c;
|
|
|
|
which don't noticeably benefit from move support. Therefore, optimal performance comes from having both
|
|
move-support, and expression templates enabled.
|
|
|
|
Note that while "moved-from" objects are left in a sane state, they have an unspecified value, and the only permitted
|
|
operations on them are destruction or the assignment of a new value. Any other operation should be considered
|
|
a programming error and all of our backends will trigger an assertion if any other operation is attempted. This behavior
|
|
allows for optimal performance on move-construction (i.e. no allocation required, we just take ownership of the existing
|
|
object's internal state), while maintaining usability in the standard library containers.
|
|
|
|
[h4:expression_templates Expression Templates]
|
|
|
|
Class `number` is expression-template-enabled: that means that rather than having a multiplication
|
|
operator that looks like this:
|
|
|
|
template <class Backend>
|
|
number<Backend> operator * (const number<Backend>& a, const number<Backend>& b)
|
|
{
|
|
number<Backend> result(a);
|
|
result *= b;
|
|
return result;
|
|
}
|
|
|
|
Instead the operator looks more like this:
|
|
|
|
template <class Backend>
|
|
``['unmentionable-type]`` operator * (const number<Backend>& a, const number<Backend>& b);
|
|
|
|
Where the '['unmentionable]' return type is an implementation detail that, rather than containing the result
|
|
of the multiplication, contains instructions on how to compute the result. In effect it's just a pair
|
|
of references to the arguments of the function, plus some compile-time information that stores what the operation
|
|
is.
|
|
|
|
The great advantage of this method is the ['elimination of temporaries]: for example, the "naive" implementation
|
|
of `operator*` above, requires one temporary for computing the result, and at least another one to return it. It's true
|
|
that sometimes this overhead can be reduced by using move-semantics, but it can't be eliminated completely. For example,
|
|
lets suppose we're evaluating a polynomial via Horner's method, something like this:
|
|
|
|
T a[7] = { /* some values */ };
|
|
//....
|
|
y = (((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0];
|
|
|
|
If type `T` is a `number`, then this expression is evaluated ['without creating a single temporary value]. In contrast,
|
|
if we were using the [mpfr_class] C++ wrapper for [mpfr] - then this expression would result in no less than 11
|
|
temporaries (this is true even though [mpfr_class] does use expression templates to reduce the number of temporaries somewhat). Had
|
|
we used an even simpler wrapper around [mpfr] like [mpreal] things would have been even worse and no less that 24 temporaries
|
|
are created for this simple expression (note - we actually measure the number of memory allocations performed rather than
|
|
the number of temporaries directly, note also that the [mpf_class] wrapper that will be supplied with GMP-5.1 reduces the number of
|
|
temporaries to pretty much zero). Note that if we compile with expression templates disabled and rvalue-reference support
|
|
on, then actually still have no wasted memory allocations as even though temporaries are created, their contents are moved
|
|
rather than copied.
|
|
[footnote The actual number generated will depend on the compiler, how well it optimizes the code, and whether it supports
|
|
rvalue references. The number of 11 temporaries was generated with Visual C++ 2010.]
|
|
|
|
[important
|
|
Expression templates can radically reorder the operations in an expression, for example:
|
|
|
|
a = (b * c) * a;
|
|
|
|
Will get transformed into:
|
|
|
|
a *= c;
|
|
a *= b;
|
|
|
|
If this is likely to be an issue for a particular application, then they should be disabled.
|
|
]
|
|
|
|
This library also extends expression template support to standard library functions like `abs` or `sin` with `number`
|
|
arguments. This means that an expression such as:
|
|
|
|
y = abs(x);
|
|
|
|
can be evaluated without a single temporary being calculated. Even expressions like:
|
|
|
|
y = sin(x);
|
|
|
|
get this treatment, so that variable 'y' is used as "working storage" within the implementation of `sin`,
|
|
thus reducing the number of temporaries used by one. Of course, should you write:
|
|
|
|
x = sin(x);
|
|
|
|
Then we clearly can't use `x` as working storage during the calculation, so then a temporary variable
|
|
is created in this case.
|
|
|
|
Given the comments above, you might be forgiven for thinking that expression-templates are some kind of universal-panacea:
|
|
sadly though, all tricks like this have their downsides. For one thing, expression template libraries
|
|
like this one, tend to be slower to compile than their simpler cousins, they're also harder to debug
|
|
(should you actually want to step through our code!), and rely on compiler optimizations being turned
|
|
on to give really good performance. Also, since the return type from expressions involving `number`s
|
|
is an "unmentionable implementation detail", you have to be careful to cast the result of an expression
|
|
to the actual number type when passing an expression to a template function. For example, given:
|
|
|
|
template <class T>
|
|
void my_proc(const T&);
|
|
|
|
Then calling:
|
|
|
|
my_proc(a+b);
|
|
|
|
Will very likely result in obscure error messages inside the body of `my_proc` - since we've passed it
|
|
an expression template type, and not a number type. Instead we probably need:
|
|
|
|
my_proc(my_number_type(a+b));
|
|
|
|
Having said that, these situations don't occur that often - or indeed not at all for non-template functions.
|
|
In addition, all the functions in the Boost.Math library will automatically convert expression-template arguments
|
|
to the underlying number type without you having to do anything, so:
|
|
|
|
mpfr_float_100 a(20), delta(0.125);
|
|
boost::math::gamma_p(a, a + delta);
|
|
|
|
Will work just fine, with the `a + delta` expression template argument getting converted to an `mpfr_float_100`
|
|
internally by the Boost.Math library.
|
|
|
|
[caution In C++11 you should never store an expression template using:
|
|
|
|
`auto my_expression = a + b - c;`
|
|
|
|
unless you're absolutely sure that the lifetimes of `a`, `b` and `c` will outlive that of `my_expression`.
|
|
|
|
In fact, it is particularly easy to create dangling references by mixing expression templates with the `auto`
|
|
keyword, for example:
|
|
|
|
`auto val = cpp_dec_float_50("23.1") * 100;`
|
|
|
|
In this situation, the integer literal is stored directly in the expression template - so its use is OK here -
|
|
but the `cpp_dec_float_50` temporary is stored by reference and then destructed when the statement completes,
|
|
leaving a dangling reference.
|
|
|
|
[*['If in doubt, do not ever mix expression templates with the `auto` keyword.]]
|
|
]
|
|
|
|
And finally... the performance improvements from an expression template library like this are often not as
|
|
dramatic as the reduction in number of temporaries would suggest. For example, if we compare this library with
|
|
[mpfr_class] and [mpreal], with all three using the underlying [mpfr] library at 50 decimal digits precision then
|
|
we see the following typical results for polynomial execution:
|
|
|
|
[table Evaluation of Order 6 Polynomial.
|
|
[[Library] [Relative Time] [Relative number of memory allocations]]
|
|
[[number] [1.0 (0.00957s)] [1.0 (2996 total)]]
|
|
[[[mpfr_class]] [1.1 (0.0102s)] [4.3 (12976 total)]]
|
|
[[[mpreal]] [1.6 (0.0151s)] [9.3 (27947 total)]]
|
|
]
|
|
|
|
As you can see, the execution time increases a lot more slowly than the number of memory allocations. There are
|
|
a number of reasons for this:
|
|
|
|
* The cost of extended-precision multiplication and division is so great, that the times taken for these tend to
|
|
swamp everything else.
|
|
* The cost of an in-place multiplication (using `operator*=`) tends to be more than an out-of-place
|
|
`operator*` (typically `operator *=` has to create a temporary workspace to carry out the multiplication, where
|
|
as `operator*` can use the target variable as workspace). Since the expression templates carry out their
|
|
magic by converting out-of-place operators to in-place ones, we necessarily take this hit. Even so the
|
|
transformation is more efficient than creating the extra temporary variable, just not by as much as
|
|
one would hope.
|
|
|
|
Finally, note that `number` takes a second template argument, which, when set to `et_off` disables all
|
|
the expression template machinery. The result is much faster to compile, but slower at runtime.
|
|
|
|
We'll conclude this section by providing some more performance comparisons between these three libraries,
|
|
again, all are using [mpfr] to carry out the underlying arithmetic, and all are operating at the same precision
|
|
(50 decimal digits):
|
|
|
|
[table Evaluation of Boost.Math's Bessel function test data
|
|
[[Library] [Relative Time] [Relative Number of Memory Allocations]]
|
|
[[mpfr_float_50] [1.0 (5.78s)] [1.0 (1611963)]]
|
|
[[number<mpfr_float_backend<50>, et_off>[br](but with rvalue reference support)]
|
|
[1.1 (6.29s)] [2.64 (4260868)]]
|
|
[[[mpfr_class]] [1.1 (6.28s)] [2.45 (3948316)]]
|
|
[[[mpreal]] [1.65 (9.54s)] [8.21 (13226029)]]
|
|
]
|
|
|
|
[table Evaluation of Boost.Math's Non-Central T distribution test data
|
|
[[Library][Relative Time][Relative Number of Memory Allocations]]
|
|
[[number] [1.0 (263s)][1.0 (127710873)]]
|
|
[[number<mpfr_float_backend<50>, et_off>[br](but with rvalue reference support)]
|
|
[1.0 (260s)][1.2 (156797871)]]
|
|
[[[mpfr_class]] [1.1 (287s)][2.1 (268336640)]]
|
|
[[[mpreal]] [1.5 (389s)][3.6 (466960653)]]
|
|
]
|
|
|
|
The above results were generated on Win32 compiling with Visual C++ 2010, all optimizations on (/Ox),
|
|
with MPFR 3.0 and MPIR 2.3.0.
|
|
|
|
[endsect] [/section:intro Introduction]
|
|
|
|
[section:tut Tutorial]
|
|
|
|
In order to use this library you need to make two choices:
|
|
|
|
* What kind of number do I want ([link boost_multiprecision.tut.ints integer],
|
|
[link boost_multiprecision.tut.floats floating-point], [link boost_multiprecision.tut.rational rational], or [link boost_multiprecision.tut.complex complex]).
|
|
* Which back-end do I want to perform the actual arithmetic (Boost-supplied, GMP, MPFR, MPC, Tommath etc)?
|
|
|
|
[section:ints Integer Types]
|
|
|
|
The following back-ends provide integer arithmetic:
|
|
|
|
[table
|
|
[[Backend Type][Header][Radix][Dependencies][Pros][Cons]]
|
|
[[`cpp_int`][boost/multiprecision/cpp_int.hpp][2][None]
|
|
[Very versatile, Boost licensed, all C++ integer type which support both [@http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic arbitrary precision] and fixed precision integer types.][Slower than [gmp], though typically not as slow as [tommath]]]
|
|
[[`gmp_int`][boost/multiprecision/gmp.hpp][2][[gmp]][Very fast and efficient back-end.][Dependency on GNU licensed [gmp] library.]]
|
|
[[`tom_int`][boost/multiprecision/tommath.hpp][2][[tommath]][Public domain back-end with no licence restrictions.][Slower than [gmp].]]
|
|
]
|
|
|
|
[section:cpp_int cpp_int]
|
|
|
|
`#include <boost/multiprecision/cpp_int.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
typedef unspecified-type limb_type;
|
|
|
|
enum cpp_integer_type { signed_magnitude, unsigned_magnitude };
|
|
enum cpp_int_check_type { checked, unchecked };
|
|
|
|
template <unsigned MinBits = 0,
|
|
unsigned MaxBits = 0,
|
|
cpp_integer_type SignType = signed_magnitude,
|
|
cpp_int_check_type Checked = unchecked,
|
|
class Allocator = std::allocator<limb_type> >
|
|
class cpp_int_backend;
|
|
//
|
|
// Expression templates default to et_off if there is no allocator:
|
|
//
|
|
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked>
|
|
struct expression_template_default<cpp_int_backend<MinBits, MaxBits, SignType, Checked, void> >
|
|
{ static const expression_template_option value = et_off; };
|
|
|
|
typedef number<cpp_int_backend<> > cpp_int; // arbitrary precision integer
|
|
typedef rational_adaptor<cpp_int_backend<> > cpp_rational_backend;
|
|
typedef number<cpp_rational_backend> cpp_rational; // arbitrary precision rational number
|
|
|
|
// Fixed precision unsigned types:
|
|
typedef number<cpp_int_backend<128, 128, unsigned_magnitude, unchecked, void> > uint128_t;
|
|
typedef number<cpp_int_backend<256, 256, unsigned_magnitude, unchecked, void> > uint256_t;
|
|
typedef number<cpp_int_backend<512, 512, unsigned_magnitude, unchecked, void> > uint512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, unsigned_magnitude, unchecked, void> > uint1024_t;
|
|
|
|
// Fixed precision signed types:
|
|
typedef number<cpp_int_backend<128, 128, signed_magnitude, unchecked, void> > int128_t;
|
|
typedef number<cpp_int_backend<256, 256, signed_magnitude, unchecked, void> > int256_t;
|
|
typedef number<cpp_int_backend<512, 512, signed_magnitude, unchecked, void> > int512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, signed_magnitude, unchecked, void> > int1024_t;
|
|
|
|
// Over again, but with checking enabled this time:
|
|
typedef number<cpp_int_backend<0, 0, signed_magnitude, checked> > checked_cpp_int;
|
|
typedef rational_adaptor<cpp_int_backend<0, 0, signed_magnitude, checked> > checked_cpp_rational_backend;
|
|
typedef number<cpp_rational_backend> checked_cpp_rational;
|
|
|
|
// Checked fixed precision unsigned types:
|
|
typedef number<cpp_int_backend<128, 128, unsigned_magnitude, checked, void> > checked_uint128_t;
|
|
typedef number<cpp_int_backend<256, 256, unsigned_magnitude, checked, void> > checked_uint256_t;
|
|
typedef number<cpp_int_backend<512, 512, unsigned_magnitude, checked, void> > checked_uint512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, unsigned_magnitude, checked, void> > checked_uint1024_t;
|
|
|
|
// Fixed precision signed types:
|
|
typedef number<cpp_int_backend<128, 128, signed_magnitude, checked, void> > checked_int128_t;
|
|
typedef number<cpp_int_backend<256, 256, signed_magnitude, checked, void> > checked_int256_t;
|
|
typedef number<cpp_int_backend<512, 512, signed_magnitude, checked, void> > checked_int512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, signed_magnitude, checked, void> > checked_int1024_t;
|
|
|
|
}} // namespaces
|
|
|
|
The `cpp_int_backend` type is normally used via one of the convenience typedefs given above.
|
|
|
|
This back-end is the "Swiss Army Knife" of integer types as it can represent both fixed and
|
|
[@http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic arbitrary precision]
|
|
integer types, and both signed and unsigned types. There are five template arguments:
|
|
|
|
[variablelist
|
|
[[MinBits][Determines the number of Bits to store directly within the object before resorting to dynamic memory
|
|
allocation. When zero, this field is determined automatically based on how many bits can be stored
|
|
in union with the dynamic storage header: setting a larger value may improve performance as larger integer
|
|
values will be stored internally before memory allocation is required.]]
|
|
[[MaxBits][Determines the maximum number of bits to be stored in the type: resulting in a fixed precision type.
|
|
When this value is the same as MinBits, then the Allocator parameter is ignored, as no dynamic
|
|
memory allocation will ever be performed: in this situation the Allocator parameter should be set to
|
|
type `void`. Note that this parameter should not be used simply to prevent large memory
|
|
allocations, not only is that role better performed by the allocator, but fixed precision
|
|
integers have a tendency to allocate all of MaxBits of storage more often than one would expect.]]
|
|
[[SignType][Determines whether the resulting type is signed or not. Note that for
|
|
[@http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic arbitrary precision] types
|
|
this parameter must be `signed_magnitude`. For fixed precision
|
|
types then this type may be either `signed_magnitude` or `unsigned_magnitude`.]]
|
|
[[Checked][This parameter has two values: `checked` or `unchecked`. See below.]]
|
|
[[Allocator][The allocator to use for dynamic memory allocation, or type `void` if MaxBits == MinBits.]]
|
|
]
|
|
|
|
When the template parameter Checked is set to `checked` then the result is a ['checked-integer], checked
|
|
and unchecked integers have the following properties:
|
|
|
|
[table
|
|
[[Condition][Checked-Integer][Unchecked-Integer]]
|
|
[[Numeric overflow in fixed precision arithmetic][Throws a `std::overflow_error`.][Performs arithmetic modulo 2[super MaxBits]]]
|
|
[[Constructing an integer from a value that can not be represented in the target type][Throws a `std::range_error`.]
|
|
[Converts the value modulo 2[super MaxBits], signed to unsigned conversions extract the last MaxBits bits of the
|
|
2's complement representation of the input value.]]
|
|
[[Unsigned subtraction yielding a negative value.][Throws a `std::range_error`.][Yields the value that would
|
|
result from treating the unsigned type as a 2's complement signed type.]]
|
|
[[Attempting a bitwise operation on a negative value.][Throws a `std::range_error`][Yields the value, but not the bit pattern,
|
|
that would result from performing the operation on a 2's complement integer type.]]
|
|
]
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `cpp_int_backend`s have the value zero.
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
* Construction from a string that contains invalid non-numeric characters results in a `std::runtime_error` being thrown.
|
|
* Since the precision of `cpp_int_backend` is necessarily limited when the allocator parameter is void,
|
|
care should be taken to avoid numeric overflow when using this type
|
|
unless you actually want modulo-arithmetic behavior.
|
|
* The type uses a sign-magnitude representation internally, so type `int128_t` has 128-bits of precision plus an extra sign bit.
|
|
In this respect the behaviour of these types differs from built-in 2's complement types. In might be tempting to use a
|
|
127-bit type instead, and indeed this does work, but behaviour is still slightly different from a 2's complement built-in type
|
|
as the min and max values are identical (apart from the sign), where as they differ by one for a true 2's complement type.
|
|
That said it should be noted that there's no requirement for built-in types to be 2's complement either - it's simply that this
|
|
is the most common format by far.
|
|
* Attempting to print negative values as either an Octal or Hexadecimal string results in a `std::runtime_error` being thrown,
|
|
this is a direct consequence of the sign-magnitude representation.
|
|
* The fixed precision types `[checked_][u]intXXX_t` have expression template support turned off - it seems to make little
|
|
difference to the performance of these types either way - so we may as well have the faster compile times by turning
|
|
the feature off.
|
|
* Unsigned types support subtraction - the result is "as if" a 2's complement operation had been performed as long as they are not
|
|
['checked-integers] (see above).
|
|
In other words they behave pretty much as a built in integer type would in this situation. So for example if we were using
|
|
`uint128_t` then `uint128_t(1)-4` would result in the value `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD`
|
|
of type `uint128_t`. However, had this operation been performed on `checked_uint128_t` then a `std::range_error` would have
|
|
been thrown.
|
|
* Unary negation of unsigned types results in a compiler error (static assertion).
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* When used at fixed precision, the size of this type is always one machine word (plus any compiler-applied alignment padding)
|
|
larger than you would expect for an N-bit integer:
|
|
the extra word stores both the sign, and how many machine words in the integer are actually in use.
|
|
The latter is an optimisation for larger fixed precision integers, so that a 1024-bit integer has almost the same performance
|
|
characteristics as a 128-bit integer, rather than being 4 times slower for addition and 16 times slower for multiplication
|
|
(assuming the values involved would always fit in 128 bits).
|
|
Typically this means you can use
|
|
an integer type wide enough for the "worst case scenario" with only minor performance degradation even if most of the time
|
|
the arithmetic could in fact be done with a narrower type.
|
|
Also note that unsigned fixed precision types small enough to fit inside the largest native integer become a simple wrapper around that type,
|
|
this includes the "checked" variants. Small signed types will always have an extra sign word and so be larger than their native equivalent.
|
|
* When used at fixed precision and MaxBits is smaller than the number of bits in the largest native integer type, then
|
|
internally `cpp_int_backend` switches to a "trivial" implementation where it is just a thin wrapper around a single
|
|
integer. Note that it will still be slightly slower than a bare native integer, as it emulates a
|
|
signed-magnitude representation rather than simply using the platforms native sign representation: this ensures
|
|
there is no step change in behavior as a cpp_int grows in size.
|
|
* Fixed precision `cpp_int`'s have some support for `constexpr` values and user-defined literals, see
|
|
[link boost_multiprecision.tut.lits here] for the full description. For example `0xfffff_cppi1024`
|
|
specifies a 1024-bit integer with the value 0xffff. This can be used to generate compile time constants that are
|
|
too large to fit into any built in number type.
|
|
* The __cpp_int types support constexpr arithmetic, provided it is a fixed precision type with no allocator. It may also
|
|
be a checked integer: in which case a compiler error will be generated on overflow or undefined behaviour. In addition
|
|
the free functions `abs`, `swap`, `multiply`, `add`, `subtract`, `divide_qr`, `integer_modulus`, `powm`, `lsb`, `msb`,
|
|
`bit_test`, `bit_set`, `bit_unset`, `bit_flip`, `sqrt`, `gcd`, `lcm` are all supported. Use of __cpp_int in this way
|
|
requires either a C++2a compiler (one which supports `std::is_constant_evaluated()`), or GCC-6 or later in C++14 mode.
|
|
Compilers other than GCC and without `std::is_constant_evaluated()` will support a very limited set of operations:
|
|
expect to hit roadblocks rather easily.
|
|
* You can import/export the raw bits of a __cpp_int to and from external storage via the `import_bits` and `export_bits`
|
|
functions. More information is in the [link boost_multiprecision.tut.import_export section on import/export].
|
|
|
|
[h5:cpp_int_eg Example:]
|
|
|
|
[cpp_int_eg]
|
|
|
|
[endsect] [/section:cpp_int cpp_int]
|
|
|
|
[section:gmp_int gmp_int]
|
|
|
|
`#include <boost/multiprecision/gmp.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class gmp_int;
|
|
|
|
typedef number<gmp_int > mpz_int;
|
|
|
|
}} // namespaces
|
|
|
|
The `gmp_int` back-end is used via the typedef `boost::multiprecision::mpz_int`. It acts as a thin wrapper around the [gmp] `mpz_t`
|
|
to provide an integer type that is a drop-in replacement for the native C++ integer types, but with unlimited precision.
|
|
|
|
As well as the usual conversions from arithmetic and string types, type `mpz_int` is copy constructible and assignable from:
|
|
|
|
* The [gmp] native types: `mpf_t`, `mpz_t`, `mpq_t`.
|
|
* Instances of `number<T>` that are wrappers around those types: `number<gmp_float<N> >`, `number<gmp_rational>`.
|
|
|
|
It's also possible to access the underlying `mpz_t` via the `data()` member function of `gmp_int`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* No changes are made to the GMP library's global settings - so you can safely mix this type with
|
|
existing code that uses [gmp].
|
|
* Default constructed `gmp_int`s have the value zero (this is GMP's default behavior).
|
|
* Formatted IO for this type does not support octal or hexadecimal notation for negative values,
|
|
as a result performing formatted output on this type when the argument is negative and either of the flags
|
|
`std::ios_base::oct` or `std::ios_base::hex` are set, will result in a `std::runtime_error` will be thrown.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid integer.
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
* Although this type is a wrapper around [gmp] it will work equally well with [mpir]. Indeed use of [mpir]
|
|
is recommended on Win32.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
|
|
[h5 Example:]
|
|
|
|
[mpz_eg]
|
|
|
|
[endsect] [/section:gmp_int gmp_int]
|
|
|
|
[section:tom_int tom_int]
|
|
|
|
`#include <boost/multiprecision/tommath.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class tommath_int;
|
|
|
|
typedef number<tommath_int > tom_int;
|
|
|
|
}} // namespaces
|
|
|
|
The `tommath_int` back-end is used via the typedef `boost::multiprecision::tom_int`. It acts as a thin wrapper around the [tommath] `tom_int`
|
|
to provide an integer type that is a drop-in replacement for the native C++ integer types, but with unlimited precision.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed objects have the value zero (this is [tommath]'s default behavior).
|
|
* Although `tom_int` is mostly a drop in replacement for the builtin integer types, it should be noted that it is a
|
|
rather strange beast as it's a signed type that is not a 2's complement type. As a result the bitwise operations
|
|
`| & ^` will throw a `std::runtime_error` exception if either of the arguments is negative. Similarly the complement
|
|
operator`~` is deliberately not implemented for this type.
|
|
* Formatted IO for this type does not support octal or hexadecimal notation for negative values,
|
|
as a result performing formatted output on this type when the argument is negative and either of the flags
|
|
`std::ios_base::oct` or `std::ios_base::hex` are set, will result in a `std::runtime_error` will be thrown.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid integer.
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
|
|
[h5 Example:]
|
|
|
|
[tommath_eg]
|
|
|
|
[endsect] [/section:tom_int tom_int]
|
|
|
|
[section:egs Examples]
|
|
|
|
[import ../example/integer_examples.cpp]
|
|
|
|
[section:factorials Factorials]
|
|
[FAC1]
|
|
[endsect] [/section:factorials Factorials]
|
|
|
|
|
|
[section:bitops Bit Operations]
|
|
[BITOPS]
|
|
[endsect] [/section:bitops Bit Operations]
|
|
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:floats floating-point Numbers]
|
|
|
|
The following back-ends provide floating-point arithmetic:
|
|
|
|
[table
|
|
[[Backend Type][Header][Radix][Dependencies][Pros][Cons]]
|
|
[[`cpp_bin_float<N>`][boost/multiprecision/cpp_bin_float.hpp][2][None][Header only, all C++ implementation. Boost licence.][Approximately 2x slower than the [mpfr] or [gmp] libraries.]]
|
|
[[`cpp_dec_float<N>`][boost/multiprecision/cpp_dec_float.hpp][10][None][Header only, all C++ implementation. Boost licence.][Approximately 2x slower than the [mpfr] or [gmp] libraries.]]
|
|
[[`mpf_float<N>`][boost/multiprecision/gmp.hpp][2][[gmp]][Very fast and efficient back-end.][Dependency on GNU licensed [gmp] library.]]
|
|
[[`mpfr_float<N>`][boost/multiprecision/mpfr.hpp][2][[gmp] and [mpfr]][Very fast and efficient back-end, with its own standard library implementation.][Dependency on GNU licensed [gmp] and [mpfr] libraries.]]
|
|
[[`float128`][boost/multiprecision/float128.hpp][2][Either [quadmath] or the Intel C++ Math library.][Very fast and efficient back-end for 128-bit floating-point values (113-bit mantissa, equivalent to FORTRAN's QUAD real)][Depends on the compiler being either recent GCC or Intel C++ versions.]]
|
|
]
|
|
|
|
[section:cpp_bin_float cpp_bin_float]
|
|
|
|
`#include <boost/multiprecision/cpp_bin_float.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
enum digit_base_type
|
|
{
|
|
digit_base_2 = 2,
|
|
digit_base_10 = 10
|
|
};
|
|
|
|
template <unsigned Digits, digit_base_type base = digit_base_10, class Allocator = void, class Exponent = int, ExponentMin = 0, ExponentMax = 0>
|
|
class cpp_bin_float;
|
|
|
|
typedef number<cpp_bin_float<50> > cpp_bin_float_50;
|
|
typedef number<cpp_bin_float<100> > cpp_bin_float_100;
|
|
|
|
typedef number<backends::cpp_bin_float<24, backends::digit_base_2, void, boost::int16_t, -126, 127>, et_off> cpp_bin_float_single;
|
|
typedef number<backends::cpp_bin_float<53, backends::digit_base_2, void, boost::int16_t, -1022, 1023>, et_off> cpp_bin_float_double;
|
|
typedef number<backends::cpp_bin_float<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_double_extended;
|
|
typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_quad;
|
|
typedef number<backends::cpp_bin_float<237, backends::digit_base_2, void, boost::int32_t, -262142, 262143>, et_off> cpp_bin_float_oct;
|
|
|
|
}} // namespaces
|
|
|
|
The `cpp_bin_float` back-end is used in conjunction with `number`: It acts as an entirely C++ (header only and dependency free)
|
|
floating-point number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
much greater precision.
|
|
|
|
Type `cpp_bin_float` can be used at fixed precision by specifying a non-zero `Digits` template parameter.
|
|
The typedefs `cpp_bin_float_50` and `cpp_bin_float_100` provide arithmetic types at 50 and 100 decimal digits precision
|
|
respectively.
|
|
|
|
Optionally, you can specify whether the precision is specified in decimal digits or binary bits - for example
|
|
to declare a `cpp_bin_float` with exactly the same precision as `double` one would use
|
|
`number<cpp_bin_float<53, digit_base_2> >`. The typedefs `cpp_bin_float_single`, `cpp_bin_float_double`,
|
|
`cpp_bin_float_quad`, `cpp_bin_float_oct` and `cpp_bin_float_double_extended` provide
|
|
software analogues of the IEEE single, double, quad and octuple float data types, plus the Intel-extended-double type respectively.
|
|
Note that while these types are functionally equivalent to the native IEEE types, but they do not have the same size
|
|
or bit-layout as true IEEE compatible types.
|
|
|
|
Normally `cpp_bin_float` allocates no memory: all of the space required for its digits are allocated
|
|
directly within the class. As a result care should be taken not to use the class with too high a digit count
|
|
as stack space requirements can grow out of control. If that represents a problem then providing an allocator
|
|
as a template parameter causes `cpp_bin_float` to dynamically allocate the memory it needs: this
|
|
significantly reduces the size of `cpp_bin_float` and increases the viable upper limit on the number of digits
|
|
at the expense of performance. However, please bear in mind that arithmetic operations rapidly become ['very] expensive
|
|
as the digit count grows: the current implementation really isn't optimized or designed for large digit counts.
|
|
Note that since the actual type of the objects allocated
|
|
is completely opaque, the suggestion would be to use an allocator with `void` `value_type`, for example:
|
|
`number<cpp_bin_float<1000, digit_base_10, std::allocator<void> > >`.
|
|
|
|
The final template parameters determine the type and range of the exponent: parameter `Exponent` can be
|
|
any signed integer type, but note that `MinExponent` and `MaxExponent` can not go right up to the limits
|
|
of the `Exponent` type as there has to be a little extra headroom for internal calculations. You will
|
|
get a compile time error if this is the case. In addition if MinExponent or MaxExponent are zero, then
|
|
the library will choose suitable values that are as large as possible given the constraints of the type
|
|
and need for extra headroom for internal calculations.
|
|
|
|
There is full standard library and `numeric_limits` support available for this type.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `cpp_bin_float`s have a value of zero.
|
|
* The radix of this type is 2, even when the precision is specified as decimal digits.
|
|
* The type supports both infinities and NaN's. An infinity is generated whenever the result would overflow,
|
|
and a NaN is generated for any mathematically undefined operation.
|
|
* There is a `std::numeric_limits` specialisation for this type.
|
|
* Any `number` instantiated on this type, is convertible to any other `number` instantiated on this type -
|
|
for example you can convert from `number<cpp_bin_float<50> >` to `number<cpp_bin_float<SomeOtherValue> >`.
|
|
Narrowing conversions round to nearest and are `explicit`.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* All arithmetic operations are correctly rounded to nearest. String conversions and the `sqrt` function
|
|
are also correctly rounded, but transcendental functions (sin, cos, pow, exp etc) are not.
|
|
|
|
[h5 cpp_bin_float example:]
|
|
|
|
[cpp_bin_float_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:cpp_dec_float cpp_dec_float]
|
|
|
|
`#include <boost/multiprecision/cpp_dec_float.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10, class ExponentType = boost::int32_t, class Allocator = void>
|
|
class cpp_dec_float;
|
|
|
|
typedef number<cpp_dec_float<50> > cpp_dec_float_50;
|
|
typedef number<cpp_dec_float<100> > cpp_dec_float_100;
|
|
|
|
}} // namespaces
|
|
|
|
The `cpp_dec_float` back-end is used in conjunction with `number`: It acts as an entirely C++ (header only and dependency free)
|
|
floating-point number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
much greater precision.
|
|
|
|
Type `cpp_dec_float` can be used at fixed precision by specifying a non-zero `Digits10` template parameter.
|
|
The typedefs `cpp_dec_float_50` and `cpp_dec_float_100` provide arithmetic types at 50 and 100 decimal digits precision
|
|
respectively. Optionally, you can specify an integer type to use for the exponent, this defaults to a 32-bit integer type
|
|
which is more than large enough for the vast majority of use cases, but larger types such as `long long` can also be specified
|
|
if you need a truly huge exponent range. In any case the ExponentType must be a built in signed integer type at least 2 bytes
|
|
and 16-bits wide.
|
|
|
|
Normally `cpp_dec_float` allocates no memory: all of the space required for its digits are allocated
|
|
directly within the class. As a result care should be taken not to use the class with too high a digit count
|
|
as stack space requirements can grow out of control. If that represents a problem then providing an allocator
|
|
as the final template parameter causes `cpp_dec_float` to dynamically allocate the memory it needs: this
|
|
significantly reduces the size of `cpp_dec_float` and increases the viable upper limit on the number of digits
|
|
at the expense of performance. However, please bear in mind that arithmetic operations rapidly become ['very] expensive
|
|
as the digit count grows: the current implementation really isn't optimized or designed for large digit counts.
|
|
|
|
There is full standard library and `numeric_limits` support available for this type.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `cpp_dec_float`s have a value of zero.
|
|
* The radix of this type is 10. As a result it can behave subtly differently from base-2 types.
|
|
* The type has a number of internal guard digits over and above those specified in the template argument.
|
|
Normally these should not be visible to the user.
|
|
* The type supports both infinities and NaN's. An infinity is generated whenever the result would overflow,
|
|
and a NaN is generated for any mathematically undefined operation.
|
|
* There is a `std::numeric_limits` specialisation for this type.
|
|
* Any `number` instantiated on this type, is convertible to any other `number` instantiated on this type -
|
|
for example you can convert from `number<cpp_dec_float<50> >` to `number<cpp_dec_float<SomeOtherValue> >`.
|
|
Narrowing conversions are truncating and `explicit`.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* The actual precision of a `cpp_dec_float` is always slightly higher than the number of digits specified in
|
|
the template parameter, actually how much higher is an implementation detail but is always at least 8 decimal
|
|
digits.
|
|
* Operations involving `cpp_dec_float` are always truncating. However, note that since their are guard digits
|
|
in effect, in practice this has no real impact on accuracy for most use cases.
|
|
|
|
[h5 cpp_dec_float example:]
|
|
|
|
[cpp_dec_float_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:gmp_float gmp_float]
|
|
|
|
`#include <boost/multiprecision/gmp.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10>
|
|
class gmp_float;
|
|
|
|
typedef number<gmp_float<50> > mpf_float_50;
|
|
typedef number<gmp_float<100> > mpf_float_100;
|
|
typedef number<gmp_float<500> > mpf_float_500;
|
|
typedef number<gmp_float<1000> > mpf_float_1000;
|
|
typedef number<gmp_float<0> > mpf_float;
|
|
|
|
}} // namespaces
|
|
|
|
The `gmp_float` back-end is used in conjunction with `number` : it acts as a thin wrapper around the [gmp] `mpf_t`
|
|
to provide an real-number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
much greater precision.
|
|
|
|
Type `gmp_float` can be used at fixed precision by specifying a non-zero `Digits10` template parameter, or
|
|
at variable precision by setting the template argument to zero. The typedefs mpf_float_50, mpf_float_100,
|
|
mpf_float_500, mpf_float_1000 provide arithmetic types at 50, 100, 500 and 1000 decimal digits precision
|
|
respectively. The typedef mpf_float provides a variable precision type whose precision can be controlled via the
|
|
`number`s member functions.
|
|
|
|
[note This type only provides standard library and `numeric_limits` support when the precision is fixed at compile time.]
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `number<mpf_float<N> >` are
|
|
copy constructible and assignable from:
|
|
|
|
* The [gmp] native types `mpf_t`, `mpz_t`, `mpq_t`.
|
|
* The `number` wrappers around those types: `number<mpf_float<M> >`, `number<gmp_int>`, `number<gmp_rational>`.
|
|
|
|
It's also possible to access the underlying `mpf_t` via the `data()` member function of `gmp_float`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `gmp_float`s have the value zero (this is the [gmp] library's default behavior).
|
|
* No changes are made to the [gmp] library's global settings, so this type can be safely mixed with
|
|
existing [gmp] code.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* It is not possible to round-trip objects of this type to and from a string and get back
|
|
exactly the same value. This appears to be a limitation of [gmp].
|
|
* Since the underlying [gmp] types have no notion of infinities or NaN's, care should be taken
|
|
to avoid numeric overflow or division by zero. That latter will result in a std::overflow_error being thrown,
|
|
while generating excessively large exponents may result in instability of the underlying [gmp]
|
|
library (in testing, converting a number with an excessively large or small exponent
|
|
to a string caused [gmp] to segfault).
|
|
* This type can equally be used with [mpir] as the underlying implementation - indeed that is
|
|
the recommended option on Win32.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
|
|
[h5 [gmp] example:]
|
|
|
|
[mpf_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:mpfr_float mpfr_float]
|
|
|
|
`#include <boost/multiprecision/mpfr.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
enum mpfr_allocation_type
|
|
{
|
|
allocate_stack,
|
|
allocate_dynamic
|
|
};
|
|
|
|
template <unsigned Digits10, mpfr_allocation_type AllocateType = allocate_dynamic>
|
|
class mpfr_float_backend;
|
|
|
|
typedef number<mpfr_float_backend<50> > mpfr_float_50;
|
|
typedef number<mpfr_float_backend<100> > mpfr_float_100;
|
|
typedef number<mpfr_float_backend<500> > mpfr_float_500;
|
|
typedef number<mpfr_float_backend<1000> > mpfr_float_1000;
|
|
typedef number<mpfr_float_backend<0> > mpfr_float;
|
|
|
|
typedef number<mpfr_float_backend<50, allocate_stack> > static_mpfr_float_50;
|
|
typedef number<mpfr_float_backend<100, allocate_stack> > static_mpfr_float_100;
|
|
|
|
}} // namespaces
|
|
|
|
The `mpfr_float_backend` type is used in conjunction with `number`: It acts as a thin wrapper around the [mpfr] `mpfr_t`
|
|
to provide an real-number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
much greater precision.
|
|
|
|
Type `mpfr_float_backend` can be used at fixed precision by specifying a non-zero `Digits10` template parameter, or
|
|
at variable precision by setting the template argument to zero. The typedefs mpfr_float_50, mpfr_float_100,
|
|
mpfr_float_500, mpfr_float_1000 provide arithmetic types at 50, 100, 500 and 1000 decimal digits precision
|
|
respectively. The typedef mpfr_float provides a variable precision type whose precision can be controlled via the
|
|
`number`s member functions.
|
|
|
|
In addition the second template parameter lets you choose between dynamic allocation (the default,
|
|
and uses MPFR's normal allocation routines),
|
|
or stack allocation (where all the memory required for the underlying data types is stored
|
|
within `mpfr_float_backend`). The latter option can result in significantly faster code, at the
|
|
expense of growing the size of `mpfr_float_backend`. It can only be used at fixed precision, and
|
|
should only be used for lower digit counts. Note that we can not guarantee that using `allocate_stack`
|
|
won't cause any calls to mpfr's allocation routines, as mpfr may call these inside it's own code.
|
|
The following table gives an idea of the performance tradeoff's at 50 decimal digits
|
|
precision[footnote Compiled with VC++10 and /Ox, with MPFR-3.0.0 and MPIR-2.3.0]:
|
|
|
|
[table
|
|
[[Type][Bessel function evaluation, relative times]]
|
|
[[`number<mpfr_float_backend<50, allocate_static>, et_on>`][1.0 (5.5s)]]
|
|
[[`number<mpfr_float_backend<50, allocate_static>, et_off>`][1.05 (5.8s)]]
|
|
[[`number<mpfr_float_backend<50, allocate_dynamic>, et_on>`][1.05 (5.8s)]]
|
|
[[`number<mpfr_float_backend<50, allocate_dynamic>, et_off>`][1.16 (6.4s)]]
|
|
]
|
|
|
|
[note This type only provides `numeric_limits` support when the precision is fixed at compile time.]
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `number<mpfr_float_backend<N> >` are
|
|
copy constructible and assignable from:
|
|
|
|
* The [gmp] native types `mpf_t`, `mpz_t`, `mpq_t`.
|
|
* The [mpfr] native type `mpfr_t`.
|
|
* The `number` wrappers around those types: `number<mpfr_float_backend<M> >`, `number<mpf_float<M> >`, `number<gmp_int>`, `number<gmp_rational>`.
|
|
|
|
It's also possible to access the underlying `mpfr_t` via the data() member function of `mpfr_float_backend`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* A default constructed `mpfr_float_backend` is set to zero (['Note that this is [*not] the default [mpfr] behavior]).
|
|
* All operations use round to nearest.
|
|
* No changes are made to [gmp] or [mpfr] global settings, so this type can coexist with existing
|
|
[mpfr] or [gmp] code.
|
|
* The code can equally use [mpir] in place of [gmp] - indeed that is the preferred option on Win32.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* Division by zero results in an infinity.
|
|
* When using the variable precision type `mpfr_float`, then copy construction and assignment ['copies the precision
|
|
of the source variable]. Likewise move construction and assignment.
|
|
* When constructing the variable precision type `mpfr_float` you can specify two arguments to the constructor - the first
|
|
is the value to assign to the variable, the second is an unsigned integer specifying the precision in decimal places. The
|
|
`assign` member function similarly has a 2-argument overload taking the value to assign and the precision. You can use this
|
|
to preserve the precision of the target variable using the somewhat arcane: `a.assign(b, a.precision())`, which assigns `b` to `a`
|
|
but preserves the precision of `a`.
|
|
|
|
[h5 [mpfr] example:]
|
|
|
|
[mpfr_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:float128 float128]
|
|
|
|
`#include <boost/multiprecision/float128.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class float128_backend;
|
|
|
|
typedef number<float128_backend, et_off> float128;
|
|
|
|
}} // namespaces
|
|
|
|
The `float128` number type is a very thin wrapper around GCC's `__float128` or Intel's `_Quad` data types
|
|
and provides an real-number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
a 113 bit mantissa, and compatible with FORTRAN's 128-bit QUAD real.
|
|
|
|
All the usual standard library and `numeric_limits` support are available, performance should be equivalent
|
|
to the underlying native types: for example the LINPACK benchmarks for GCC's `__float128` and
|
|
`boost::multiprecision::float128` both achieved 5.6 MFLOPS[footnote On 64-bit Ubuntu 11.10, GCC-4.8.0, Intel Core 2 Duo T5800.].
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `float128` are
|
|
copy constructible and assignable from GCC's `__float128` and Intel's `_Quad` data types.
|
|
|
|
It's also possible to access the underlying `__float128` or `_Quad` type via the `data()` member
|
|
function of `float128_backend`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `float128`s have the value zero.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* This type is fully `constexpr` aware - basic constexpr arithmetic is supported from C++14 and onwards, comparisons,
|
|
plus the functions `fabs`, `abs`, `fpclassify`, `isnormal`, `isfinite`, `isinf` and `isnan` are also supported if either
|
|
the compiler implements C++20's `std::is_constant_evaluated()`, or if the compiler is GCC.
|
|
* It is not possible to round-trip objects of this type to and from a string and get back
|
|
exactly the same value when compiled with Intel's C++ compiler and using `_Quad` as the underlying type: this is a current limitation of
|
|
our code. Round tripping when using `__float128` as the underlying type is possible (both for GCC and Intel).
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* Division by zero results in an infinity being produced.
|
|
* Type `float128` can be used as a literal type (constexpr support).
|
|
* Type `float128` can be used for full `constexpr` arithmetic from C++14 and later with GCC. The functions `abs`, `fabs`,
|
|
`fpclassify`, `isnan`, `isinf`, `isfinite` and `isnormal` are also `constexpr`, but the transcendental functions are not.
|
|
* When using the Intel compiler, the underlying type defaults to `__float128` if it's available and `_Quad` if not. You can override
|
|
the default by defining either `BOOST_MP_USE_FLOAT128` or `BOOST_MP_USE_QUAD`.
|
|
* When the underlying type is Intel's `_Quad` type, the code must be compiled with the compiler option `-Qoption,cpp,--extended_float_type`.
|
|
* When compiling with `gcc`, you need to use the flag `--std=gnu++11/14/17`, as the suffix 'Q' is a GNU extension. Compilation fails with the flag `--std=c++11/14/17`
|
|
unless you also use `-fext-numeric-literals`.
|
|
|
|
[h5 float128 example:]
|
|
|
|
[float128_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:fp_eg Examples]
|
|
|
|
[import ../example/floating_point_examples.cpp]
|
|
|
|
[section:aos Area of Circle]
|
|
|
|
[AOS1]
|
|
[AOS2]
|
|
[AOS3]
|
|
|
|
[endsect]
|
|
|
|
[section:jel Defining a Special Function.]
|
|
|
|
[JEL]
|
|
|
|
[endsect]
|
|
|
|
[section:nd Calculating a Derivative]
|
|
|
|
[ND1]
|
|
[ND2]
|
|
[ND3]
|
|
|
|
[endsect]
|
|
|
|
[section:gi Calculating an Integral]
|
|
|
|
[GI1]
|
|
[GI2]
|
|
|
|
[endsect]
|
|
|
|
[section:poly_eg Polynomial Evaluation]
|
|
|
|
[POLY]
|
|
|
|
[endsect] [/section:poly_eg Polynomial Evaluation]
|
|
|
|
[section:variable_precision Variable Precision Newton Evaluation]
|
|
|
|
[mpfr_variable]
|
|
|
|
[endsect]
|
|
|
|
[endsect] [/section:fp_eg Examples]
|
|
|
|
[endsect] [/section:floats floating-point Numbers]
|
|
|
|
[section:interval Interval Number Types]
|
|
|
|
There is one currently only one interval number type supported - [mpfi].
|
|
|
|
[section:mpfi mpfi_float]
|
|
|
|
`#include <boost/multiprecision/mpfi.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10>
|
|
class mpfi_float_backend;
|
|
|
|
typedef number<mpfi_float_backend<50> > mpfi_float_50;
|
|
typedef number<mpfi_float_backend<100> > mpfifloat_100;
|
|
typedef number<mpfi_float_backend<500> > mpfifloat_500;
|
|
typedef number<mpfi_float_backend<1000> > mpfi_float_1000;
|
|
typedef number<mpfi_float_backend<0> > mpfi_float;
|
|
|
|
}} // namespaces
|
|
|
|
The `mpfi_float_backend` type is used in conjunction with `number`: It acts as a thin wrapper around the [mpfi] `mpfi_t`
|
|
to provide an real-number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
much greater precision and implementing interval arithmetic.
|
|
|
|
Type `mpfi_float_backend` can be used at fixed precision by specifying a non-zero `Digits10` template parameter, or
|
|
at variable precision by setting the template argument to zero. The `typedef`s `mpfi_float_50`, `mpfi_float_100`,
|
|
`mpfi_float_500`, `mpfi_float_1000` provide arithmetic types at 50, 100, 500 and 1000 decimal digits precision
|
|
respectively. The `typedef mpfi_float` provides a variable precision type whose precision can be controlled via the
|
|
`number`s member functions.
|
|
|
|
[note This type only provides `numeric_limits` support when the precision is fixed at compile time.]
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `number<mpfi_float_backend<N> >` are
|
|
copy constructible and assignable from:
|
|
|
|
* The [mpfi] native type `mpfi_t`.
|
|
* The `number` wrappers around [mpfi] or [mpfr]: `number<mpfi_float_backend<M> >` and `number<mpfr_float<M> >`.
|
|
* There is a two argument constructor taking two `number<mpfr_float<M> >` arguments specifying the interval.
|
|
|
|
It's also possible to access the underlying `mpfi_t` via the data() member function of `mpfi_float_backend`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* A default constructed `mpfi_float_backend` is set to zero (['Note that this is [*not] the default [mpfi] behavior]).
|
|
* No changes are made to [gmp] or [mpfr] global settings, so this type can coexist with existing
|
|
[mpfr] or [gmp] code.
|
|
* The code can equally use [mpir] in place of [gmp] - indeed that is the preferred option on Win32.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* Division by zero results in an infinity.
|
|
|
|
There are some additional non member functions for working on intervals:
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
number<mpfr_float_backend<Digits10>, ExpressionTemplates> lower(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& val);
|
|
|
|
Returns the lower end of the interval.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
number<mpfr_float_backend<Digits10>, ExpressionTemplates> upper(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& val);
|
|
|
|
Returns the upper end of the interval.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
number<mpfr_float_backend<Digits10>, ExpressionTemplates> median(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& val);
|
|
|
|
Returns the mid point of the interval.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
number<mpfr_float_backend<Digits10>, ExpressionTemplates> width(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& val);
|
|
|
|
Returns the absolute width of the interval.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
number<mpfi_float_backend<Digits10>, ExpressionTemplates> intersect(
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a,
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& b);
|
|
|
|
Returns the interval which is the intersection of the ['a] and ['b]. Returns an
|
|
unspecified empty interval if there is no such intersection.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
number<mpfi_float_backend<Digits10>, ExpressionTemplates> hull(
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a,
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& b);
|
|
|
|
Returns the interval which is the union of ['a] and ['b].
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
bool overlap(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a,
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& b);
|
|
|
|
Returns `true` only if the intervals ['a] and ['b] overlap.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates1, expression_template_option ExpressionTemplates2>
|
|
bool in(const number<mpfr_float_backend<Digits10>, ExpressionTemplates1>& a,
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates2>& b);
|
|
|
|
Returns `true` only if point ['a] is contained within the interval ['b].
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
bool zero_in(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a);
|
|
|
|
Returns `true` only if the interval ['a] contains the value zero.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
bool subset(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a,
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& b);
|
|
|
|
Returns `true` only if ['a] is a subset of ['b].
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
bool proper_subset(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a,
|
|
const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& b);
|
|
|
|
Returns `true` only if ['a] is a proper subset of ['b].
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
bool empty(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a);
|
|
|
|
Returns `true` only if ['a] is an empty interval, equivalent to `upper(a) < lower(a)`.
|
|
|
|
template <unsigned Digits10, expression_template_option ExpressionTemplates>
|
|
bool singleton(const number<mpfi_float_backend<Digits10>, ExpressionTemplates>& a);
|
|
|
|
Returns `true` if `lower(a) == upper(a)`.
|
|
|
|
[h5 [mpfi] example:]
|
|
|
|
[mpfi_eg]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:complex Complex Number Types]
|
|
|
|
The following backends provide complex number arithmetic:
|
|
|
|
[table
|
|
[[Backend Type][Header][Radix][Dependencies][Pros][Cons]]
|
|
[[`cpp_complex`][boost/multiprecision/cpp_complex.hpp][2][None][An all C++ Boost-licensed implementation.][Slower than [mpc].]]
|
|
[[`mpc`][boost/multiprecision/mpc.hpp][2][[mpc]][Very fast and efficient back-end.][Dependency on LGLP-licensed [MPC] library.]]
|
|
[[`compplex128`][boost/multiprecision/complex128.hpp][2][`__float128` and libquadmath][Very fast and efficient number type.][128-bit precision only, and resticted to GCC.]]
|
|
[[`complex_adaptor`][boost/multiprecision/complex_adaptor.hpp][-][none][Can convert any backend type into a complex number backend.][Not a numbe rin it's own right, and hard to use as a result.]]
|
|
]
|
|
|
|
[section:cpp_complex cpp_complex]
|
|
|
|
`#include <boost/multiprecision/cpp_complex.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits, backends::digit_base_type DigitBase = backends::digit_base_10, class Allocator = void, class Exponent = int, Exponent MinExponent = 0, Exponent MaxExponent = 0>
|
|
using cpp_complex_backend = complex_adaptor<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> >;
|
|
|
|
template <unsigned Digits, backends::digit_base_type DigitBase = digit_base_10, class Allocator = void, class Exponent = int, Exponent MinExponent = 0, Exponent MaxExponent = 0, expression_template_option ExpressionTemplates = et_off>
|
|
using cpp_complex = number<complex_adaptor<cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinExponent, MaxExponent> >, ExpressionTemplates>;
|
|
|
|
typedef cpp_complex<50> cpp_complex_50;
|
|
typedef cpp_complex<100> cpp_complex_100;
|
|
|
|
typedef cpp_complex<24, backends::digit_base_2, void, boost::int16_t, -126, 127> cpp_complex_single;
|
|
typedef cpp_complex<53, backends::digit_base_2, void, boost::int16_t, -1022, 1023> cpp_complex_double;
|
|
typedef cpp_complex<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383> cpp_complex_extended;
|
|
typedef cpp_complex<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383> cpp_complex_quad;
|
|
typedef cpp_complex<237, backends::digit_base_2, void, boost::int32_t, -262142, 262143> cpp_complex_oct;
|
|
|
|
|
|
}} // namespaces
|
|
|
|
The `cpp_complex_backend` back-end is used in conjunction with `number`: It acts as an entirely C++ (header only and dependency free)
|
|
complex number type that is a drop-in replacement for `std::complex`, but with much greater precision.
|
|
|
|
The template alias `cpp_complex` avoids the need to use class `number` directly.
|
|
|
|
Type `cpp_complex` can be used at fixed precision by specifying a non-zero `Digits` template parameter.
|
|
The typedefs `cpp_complex_50` and `cpp_complex_100` provide complex number types at 50 and 100 decimal digits precision
|
|
respectively.
|
|
|
|
Optionally, you can specify whether the precision is specified in decimal digits or binary bits - for example
|
|
to declare a `cpp_complex` with exactly the same precision as `std::complex<double>` one would use
|
|
`cpp_complex<53, digit_base_2>`. The typedefs `cpp_complex_single`, `cpp_complex_double`,
|
|
`cpp_complex_quad`, `cpp_complex_oct` and `cpp_complex_double_extended` provide
|
|
software analogues of the IEEE single, double, quad and octuple float data types, plus the Intel-extended-double type respectively.
|
|
Note that while these types are functionally equivalent to the native IEEE types, but they do not have the same size
|
|
or bit-layout as true IEEE compatible types.
|
|
|
|
Normally `cpp_complex` allocates no memory: all of the space required for its digits are allocated
|
|
directly within the class. As a result care should be taken not to use the class with too high a digit count
|
|
as stack space requirements can grow out of control. If that represents a problem then providing an allocator
|
|
as a template parameter causes `cpp_complex` to dynamically allocate the memory it needs: this
|
|
significantly reduces the size of `cpp_complex` and increases the viable upper limit on the number of digits
|
|
at the expense of performance. However, please bear in mind that arithmetic operations rapidly become ['very] expensive
|
|
as the digit count grows: the current implementation really isn't optimized or designed for large digit counts.
|
|
Note that since the actual type of the objects allocated
|
|
is completely opaque, the suggestion would be to use an allocator with `char` `value_type`, for example:
|
|
`cpp_complex<1000, digit_base_10, std::allocator<char> >`.
|
|
|
|
The next template parameters determine the type and range of the exponent: parameter `Exponent` can be
|
|
any signed integer type, but note that `MinExponent` and `MaxExponent` can not go right up to the limits
|
|
of the `Exponent` type as there has to be a little extra headroom for internal calculations. You will
|
|
get a compile time error if this is the case. In addition if MinExponent or MaxExponent are zero, then
|
|
the library will choose suitable values that are as large as possible given the constraints of the type
|
|
and need for extra headroom for internal calculations.
|
|
|
|
Finally, as with class `number`, the final template parameter determines whether expression templates are turn
|
|
on or not. Since by default this type allocates no memory, expression template support is off by default.
|
|
However, you should probably turn it on if you specify an allocator.
|
|
|
|
There is full standard library support available for this type, comparable with what `std::complex` provides.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `cpp_complex`s have a value of zero.
|
|
* The radix of this type is 2, even when the precision is specified as decimal digits.
|
|
* The type supports both infinities and NaN's. An infinity is generated whenever the result would overflow,
|
|
and a NaN is generated for any mathematically undefined operation.
|
|
* There is no `std::numeric_limits` specialisation for this type: this is the same behaviour as `std::complex`. If you need
|
|
`std::numeric_limits` support you need to look at `std::numeric_limits<my_complex_number_type::value_type>`.
|
|
* Any `number` instantiated on this type, is convertible to any other `number` instantiated on this type -
|
|
for example you can convert from `number<cpp_complex<50> >` to `number<cpp_bin_float<SomeOtherValue> >`.
|
|
Narrowing conversions round to nearest and are `explicit`.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid complex number.
|
|
|
|
[h5 example:]
|
|
|
|
[cpp_complex_eg]
|
|
|
|
Which produces the output (for the multiprecision type):
|
|
|
|
[cpp_complex_out]
|
|
|
|
[endsect]
|
|
|
|
[section:mpc_complex mpc_complex]
|
|
|
|
`#include <boost/multiprecision/mpc.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10>
|
|
class mpc_complex_backend;
|
|
|
|
typedef number<mpc_complex_backend<50> > mpc_complex_50;
|
|
typedef number<mpc_complex_backend<100> > mpc_complex_100;
|
|
typedef number<mpc_complex_backend<500> > mpc_complex_500;
|
|
typedef number<mpc_complex_backend<1000> > mpc_complex_1000;
|
|
typedef number<mpc_complex_backend<0> > mpc_complex;
|
|
|
|
}} // namespaces
|
|
|
|
The `mpc_complex_backend` type is used in conjunction with `number`: It acts as a thin wrapper around the [mpc] `mpc_t`
|
|
to provide an real-number type that is a drop-in replacement for `std::complex`, but with
|
|
much greater precision.
|
|
|
|
Type `mpc_complex_backend` can be used at fixed precision by specifying a non-zero `Digits10` template parameter, or
|
|
at variable precision by setting the template argument to zero. The typedefs mpc_complex_50, mpc_complex_100,
|
|
mpc_complex_500, mpc_complex_1000 provide complex types at 50, 100, 500 and 1000 decimal digits precision
|
|
respectively. The typedef mpc_complex provides a variable precision type whose precision can be controlled via the
|
|
`number`s member functions.
|
|
|
|
The `mpc` backend should allow use of the same syntax as the C++ standard library complex type.
|
|
When using this backend, remember to link with the flags `-lmpc -lmpfr -lgmp`.
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `number<mpc_complex_backend<N> >` are
|
|
copy constructible and assignable from:
|
|
|
|
* The [gmp] native types `mpf_t`, `mpz_t`, `mpq_t`.
|
|
* The [mpfr] native type `mpfr_t`.
|
|
* The [mpc] native type `mpc_t`.
|
|
* The `number` wrappers around those types: `number<mpfr_float_backend<M> >`, `number<mpf_float<M> >`, `number<gmp_int>`, `number<gmp_rational>`.
|
|
|
|
It's also possible to access the underlying `mpc_t` via the data() member function of `mpfr_float_backend`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* A default constructed `mpc_complex_backend` is set to zero (['Note that this is [*not] the default [mpc] behavior]).
|
|
* All operations use round to nearest.
|
|
* No changes are made to [mpc], [gmp] or [mpfr] global settings, so this type can coexist with existing
|
|
[mpc], [mpfr] or [gmp] code.
|
|
* The code can equally use [mpir] in place of [gmp] - indeed that is the preferred option on Win32.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid complex number.
|
|
* Division by zero results in a complex-infinity.
|
|
* Unlike `std::complex`, you can not use `reinterpret_cast` to treat this type as an array of the underlying floating point type.
|
|
* Unlike `std::complex`, there are no literals for imaginary values.
|
|
* When using the variable precision type `mpc_complex`, then copy construction and assignment ['copies the precision
|
|
of the source variable]. Likewise move construction and assignment.
|
|
* When constructing the variable precision type `mpc_complex` you can specify two arguments to the constructor - the first
|
|
is the value to assign to the variable, the second is an unsigned integer specifying the precision in decimal places. The
|
|
`assign` member function similarly has a 2-argument overload taking the value to assign and the precision. You can use this
|
|
to preserve the precision of the target variable using the somewhat arcane: `a.assign(b, a.precision())`, which assigns `b` to `a`
|
|
but preserves the precision of `a`.
|
|
|
|
[h5 [mpc] example:]
|
|
|
|
[mpc_eg]
|
|
|
|
Which produces the output (for the multiprecision type):
|
|
|
|
[mpc_out]
|
|
|
|
[endsect]
|
|
|
|
[section:complex128 complex128]
|
|
|
|
`#include <boost/multiprecision/complex128.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class complex128_backend;
|
|
|
|
typedef number<complex128_backend, et_off> complex128;
|
|
|
|
}} // namespaces
|
|
|
|
The `complex128` number type is a very thin wrapper around GCC's `__float128` or Intel's `_Quad` data types
|
|
and provides a complex-number type that is a drop-in replacement for the native C++ floating-point types, but with
|
|
a 113 bit mantissa, and compatible with FORTRAN's 128-bit QUAD real.
|
|
|
|
All the usual standard library functions are available, performance should be equivalent
|
|
to the underlying native types.
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `float128` are
|
|
copy constructible and assignable from GCC's `__float128` and Intel's `_Quad` data types.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `complex128`s have the value zero.
|
|
* This backend supports rvalue-references and is move-aware, making instantiations of `number` on this backend move aware.
|
|
* It is not possible to round-trip objects of this type to and from a string and get back
|
|
exactly the same value when compiled with Intel's C++ compiler and using `_Quad` as the underlying type: this is a current limitation of
|
|
our code. Round tripping when using `__float128` as the underlying type is possible (both for GCC and Intel).
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be interpreted
|
|
as a valid floating-point number.
|
|
* Division by zero results in an infinity being produced.
|
|
* When using the Intel compiler, the underlying type defaults to `__float128` if it's available and `_Quad` if not. You can override
|
|
the default by defining either `BOOST_MP_USE_FLOAT128` or `BOOST_MP_USE_QUAD`.
|
|
* When the underlying type is Intel's `_Quad` type, the code must be compiled with the compiler option `-Qoption,cpp,--extended_float_type`.
|
|
|
|
[h5 complex128 example:]
|
|
|
|
[complex128_eg]
|
|
|
|
Which results in the output:
|
|
|
|
[complex128_out]
|
|
|
|
[endsect]
|
|
|
|
[section:complex_adaptor complex_adaptor]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <class Backend>
|
|
struct complex_adaptor;
|
|
|
|
}}
|
|
|
|
Class template `complex_adaptor` is designed to sit inbetween class `number` and an actual floating point backend,
|
|
in order to create a new complex number type.
|
|
|
|
It is the means by which we implement __cpp_complex and __complex128.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:rational Rational Number Types]
|
|
|
|
The following back-ends provide rational number arithmetic:
|
|
|
|
[table
|
|
[[Backend Type][Header][Radix][Dependencies][Pros][Cons]]
|
|
[[`cpp_rational`][boost/multiprecision/cpp_int.hpp][2][None][An all C++ Boost-licensed implementation.][Slower than [gmp].]]
|
|
[[`gmp_rational`][boost/multiprecision/gmp.hpp][2][[gmp]][Very fast and efficient back-end.][Dependency on GNU licensed [gmp] library.]]
|
|
[[`tommath_rational`][boost/multiprecision/tommath.hpp][2][[tommath]][All C/C++ implementation that's Boost Software Licence compatible.][Slower than [gmp].]]
|
|
[[`rational_adaptor`][boost/multiprecision/rational_adaptor.hpp][N/A][none][All C++ adaptor that allows any integer back-end type to be used as a rational type.][Requires an underlying integer back-end type.]]
|
|
[[`boost::rational`][boost/rational.hpp][N/A][None][A C++ rational number type that can used with any `number` integer type.][The expression templates used by `number` end up being "hidden" inside `boost::rational`: performance may well suffer as a result.]]
|
|
]
|
|
|
|
[section:cpp_rational cpp_rational]
|
|
|
|
`#include <boost/multiprecision/cpp_int.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
typedef rational_adaptor<cpp_int_backend<> > cpp_rational_backend;
|
|
|
|
typedef number<cpp_rational_backend> cpp_rational;
|
|
|
|
}} // namespaces
|
|
|
|
The `cpp_rational_backend` type is used via the typedef `boost::multiprecision::cpp_rational`. It provides
|
|
a rational number type that is a drop-in replacement for the native C++ number types, but with unlimited precision.
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `cpp_rational` are copy constructible
|
|
and assignable from type `cpp_int`.
|
|
|
|
There is also a two argument constructor that accepts a numerator and denominator: both of type `cpp_int`.
|
|
|
|
There are also non-member functions:
|
|
|
|
cpp_int numerator(const cpp_rational&);
|
|
cpp_int denominator(const cpp_rational&);
|
|
|
|
which return the numerator and denominator of the number.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `cpp_rational`s have the value zero.
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be
|
|
interpreted as a valid rational number.
|
|
|
|
[h5 Example:]
|
|
|
|
[cpp_rational_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:gmp_rational gmp_rational]
|
|
|
|
`#include <boost/multiprecision/gmp.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class gmp_rational;
|
|
|
|
typedef number<gmp_rational > mpq_rational;
|
|
|
|
}} // namespaces
|
|
|
|
The `gmp_rational` back-end is used via the typedef `boost::multiprecision::mpq_rational`. It acts as a thin wrapper around the [gmp] `mpq_t`
|
|
to provide a rational number type that is a drop-in replacement for the native C++ number types, but with unlimited precision.
|
|
|
|
As well as the usual conversions from arithmetic and string types, instances of `number<gmp_rational>` are copy constructible
|
|
and assignable from:
|
|
|
|
* The [gmp] native types: `mpz_t`, `mpq_t`.
|
|
* `number<gmp_int>`.
|
|
|
|
There is also a two-argument constructor that accepts a numerator and denominator (both of type `number<gmp_int>`).
|
|
|
|
There are also non-member functions:
|
|
|
|
mpz_int numerator(const mpq_rational&);
|
|
mpz_int denominator(const mpq_rational&);
|
|
|
|
which return the numerator and denominator of the number.
|
|
|
|
It's also possible to access the underlying `mpq_t` via the `data()` member function of `mpq_rational`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `mpq_rational`s have the value zero (this is the [gmp] default behavior).
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be
|
|
interpreted as a valid rational number.
|
|
* No changes are made to the [gmp] library's global settings, so this type can coexist with existing
|
|
[gmp] code.
|
|
* The code can equally be used with [mpir] as the underlying library - indeed that is the preferred option on Win32.
|
|
|
|
[h5 Example:]
|
|
|
|
[mpq_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:tommath_rational tommath_rational]
|
|
|
|
`#include <boost/multiprecision/tommath.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
typedef rational_adpater<tommath_int> tommath_rational;
|
|
typedef number<tommath_rational > tom_rational;
|
|
|
|
}} // namespaces
|
|
|
|
The `tommath_rational` back-end is used via the typedef `boost::multiprecision::tom_rational`. It acts as a thin wrapper around
|
|
`boost::rational<tom_int>`
|
|
to provide a rational number type that is a drop-in replacement for the native C++ number types, but with unlimited precision.
|
|
|
|
The advantage of using this type rather than `boost::rational<tom_int>` directly, is that it is expression-template enabled,
|
|
greatly reducing the number of temporaries created in complex expressions.
|
|
|
|
There are also non-member functions:
|
|
|
|
tom_int numerator(const tom_rational&);
|
|
tom_int denominator(const tom_rational&);
|
|
|
|
which return the numerator and denominator of the number.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* Default constructed `tom_rational`s have the value zero (this the inherited Boost.Rational behavior).
|
|
* Division by zero results in a `std::overflow_error` being thrown.
|
|
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be
|
|
interpreted as a valid rational number.
|
|
* No changes are made to [tommath]'s global state, so this type can safely coexist with other [tommath] code.
|
|
* Performance of this type has been found to be pretty poor - this need further investigation - but it appears that Boost.Rational
|
|
needs some improvement in this area.
|
|
|
|
[h5 Example:]
|
|
|
|
[mp_rat_eg]
|
|
|
|
[endsect]
|
|
|
|
[section:br Use With Boost.Rational]
|
|
|
|
All of the integer types in this library can be used as template arguments to `boost::rational<IntType>`.
|
|
|
|
Note that using the library in this way largely negates the effect of the expression templates in `number`.
|
|
|
|
[endsect]
|
|
|
|
[section:rational_adaptor rational_adaptor]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <class IntBackend>
|
|
class rational_adpater;
|
|
|
|
}}
|
|
|
|
The class template `rational_adaptor` is a back-end for `number` which converts any existing integer back-end
|
|
into a rational-number back-end.
|
|
|
|
So for example, given an integer back-end type `MyIntegerBackend`, the use would be something like:
|
|
|
|
typedef number<MyIntegerBackend> MyInt;
|
|
typedef number<rational_adaptor<MyIntegerBackend> > MyRational;
|
|
|
|
MyRational r = 2;
|
|
r /= 3;
|
|
MyInt i = numerator(r);
|
|
assert(i == 2);
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:misc Miscellaneous Number Types.]
|
|
|
|
Backend types listed in this section are predominantly designed to aid debugging.
|
|
|
|
[section:logged_adaptor logged_adaptor]
|
|
|
|
`#include <boost/multiprecision/logged_adaptor.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <class Backend>
|
|
void log_postfix_event(const Backend& result, const char* event_description);
|
|
template <class Backend, class T>
|
|
void log_postfix_event(const Backend& result1, const T& result2, const char* event_description);
|
|
|
|
template <class Backend>
|
|
void log_prefix_event(const Backend& arg1, const char* event_description);
|
|
template <class Backend, class T>
|
|
void log_prefix_event(const Backend& arg1, const T& arg2, const char* event_description);
|
|
template <class Backend, class T, class U>
|
|
void log_prefix_event(const Backend& arg1, const T& arg2, const U& arg3, const char* event_description);
|
|
template <class Backend, class T, class U, class V>
|
|
void log_prefix_event(const Backend& arg1, const T& arg2, const U& arg3, const V& arg4, const char* event_description);
|
|
|
|
template <Backend>
|
|
class logged_adaptor;
|
|
|
|
}} // namespaces
|
|
|
|
The `logged_adaptor` type is used in conjunction with `number` and some other backend type: it acts as a thin wrapper around
|
|
some other backend to class `number` and logs all the events that take place on that object. Before any number operation takes
|
|
place, it calls `log_prefix_event` with the arguments to the operation (up to 4), plus a string describing the operation.
|
|
Then after the operation it calls `log_postfix_event` with the result of the operation, plus a string describing the operation.
|
|
Optionally, `log_postfix_event` takes a second result argument: this occurs when the result of the operation is not a `number`,
|
|
for example when `fpclassify` is called, `log_postfix_event` will be called with `result1` being the argument to the function, and
|
|
`result2` being the integer result of `fpclassify`.
|
|
|
|
The default versions of `log_prefix_event` and `log_postfix_event` do nothing, it is therefore up to the user to overload these
|
|
for the particular backend being observed.
|
|
|
|
This type provides `numeric_limits` support whenever the template argument Backend does so.
|
|
|
|
This type is particularly useful when combined with an interval number type - in this case we can use `log_postfix_event`
|
|
to monitor the error accumulated after each operation. We could either set some kind of trap whenever the accumulated error
|
|
exceeds some threshold, or simply print out diagnostic information. Using this technique we can quickly locate the cause of
|
|
numerical instability in a particular routine. The following example demonstrates this technique in a trivial algorithm
|
|
that deliberately introduces cancellation error:
|
|
|
|
[logged_adaptor]
|
|
|
|
When we examine program output we can clearly see that the diameter of the interval increases after each subtraction:
|
|
|
|
[logged_adaptor_output]
|
|
|
|
[endsect]
|
|
|
|
[section:debug_adaptor debug_adaptor]
|
|
|
|
`#include <boost/multiprecision/debug_adaptor.hpp>`
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <Backend>
|
|
class debug_adaptor;
|
|
|
|
}} // namespaces
|
|
|
|
The `debug_adaptor` type is used in conjunction with `number` and some other backend type: it acts as a thin wrapper around
|
|
some other backend to class `number` and intercepts all operations on that object storing the result as a string within itself.
|
|
|
|
This type provides `numeric_limits` support whenever the template argument Backend does so.
|
|
|
|
This type is particularly useful when your debugger provides a good view of `std::string`: when this is the case
|
|
multiprecision values can easily be inspected in the debugger by looking at the `debug_value` member of `debug_adaptor`.
|
|
The down side of this approach is that runtimes are much slower when using this type. Set against that it can make
|
|
debugging very much easier, certainly much easier than sprinkling code with `printf` statements.
|
|
|
|
When used in conjunction with the Visual C++ debugger visualisers, the value of a multiprecision type that uses this
|
|
backend is displayed in the debugger just a builtin value would be, here we're inspecting a value of type
|
|
`number<debug_adaptor<cpp_dec_float<50> > >`:
|
|
|
|
[$../debugger1.png]
|
|
|
|
Otherwise you will need to expand out the view and look at the "debug_value" member:
|
|
|
|
[$../debugger2.png]
|
|
|
|
It works for all the backend types equally too, here it is inspecting a `number<debug_adaptor<gmp_rational> >`:
|
|
|
|
[$../debugger3.png]
|
|
|
|
|
|
[endsect]
|
|
|
|
[section:visualizers Visual C++ Debugger Visualizers]
|
|
|
|
Let's face it debugger multiprecision numbers is hard - simply because we can't easily inspect the value of the numbers.
|
|
Visual C++ provides a partial solution in the shape of "visualizers" which provide improved views of complex data structures,
|
|
these visualizers need to be added to the `[Visualizer]` section of `autoexp.dat` located in the `Common7/Packages/Debugger`
|
|
directory of your Visual Studio installation. The actual visualizer code is in the sandbox
|
|
[@https://svn.boost.org/svn/boost/sandbox/boost_docs/subprojects/DebuggerVisualizers/multiprecision.vis.txt here] - just cut and paste the code
|
|
into your `autoexp.dat` file.
|
|
|
|
[note These visualizers have only been tested with VC10, also given the ability of buggy visualizers to crash your Visual C++
|
|
debugger, make sure you back up `autoexp.dat` file before using these!!]
|
|
|
|
The first visualizer provides improved views of `debug_adaptor`:
|
|
|
|
[$../debugger1.png]
|
|
|
|
The next visualizer provides improved views of cpp_int: small numbers are displayed as actual values, while larger numbers are
|
|
displayed as an array of hexadecimal parts, with the most significant part first.
|
|
|
|
Here's what it looks like for small values:
|
|
|
|
[$../debugger4.png]
|
|
|
|
And for larger values:
|
|
|
|
[$../debugger5.png]
|
|
|
|
There is also a `~raw` child member that
|
|
lets you see the actual members of the class:
|
|
|
|
[$../debugger6.png]
|
|
|
|
The visualizer for `cpp_dec_float` shows the first few digits of the value in the preview field, and the full array of digits
|
|
when you expand the view. As before the `~raw` child gives you access to the actual data members:
|
|
|
|
[$../debugger7.png]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:conversions Constructing and Interconverting Between Number Types]
|
|
|
|
All of the number types that are based on `number` have certain conversion rules in common.
|
|
In particular:
|
|
|
|
* Any number type can be constructed (or assigned) from any builtin arithmetic type, as long
|
|
as the conversion isn't lossy (for example float to int conversion):
|
|
|
|
cpp_dec_float_50 df(0.5); // OK construction from double
|
|
cpp_int i(450); // OK constructs from signed int
|
|
cpp_int j = 3.14; // Error, lossy conversion.
|
|
|
|
* A number can be explicitly constructed from an arithmetic type, even when the conversion is lossy:
|
|
|
|
cpp_int i(3.14); // OK explicit conversion
|
|
i = static_cast<cpp_int>(3.14) // OK explicit conversion
|
|
i.assign(3.14); // OK, explicit assign and avoid a temporary from the cast above
|
|
i = 3.14; // Error, no implicit assignment operator for lossy conversion.
|
|
cpp_int j = 3.14; // Error, no implicit constructor for lossy conversion.
|
|
|
|
* A `number` can be converted to any built in type, via the `convert_to` member function:
|
|
|
|
mpz_int z(2);
|
|
int i = z.convert_to<int>(); // sets i to 2
|
|
|
|
* Conversions to rational numbers from floating-point ones are always allowed, and are exact and implicit
|
|
as long as the rational number uses an unbounded integer type. Please be aware that constructing a rational
|
|
number from an extended precision floating-point type with a large exponent range can effectively run the system
|
|
out of memory, as in the extreme case ['2[super max_exponent] / CHAR_BITS] bytes of storage may be required. This
|
|
does not represent a problem for built in floating-point types however, as the exponent range for these is rather
|
|
limited.
|
|
|
|
* Conversions to floating-point numbers from rational ones are rounded to nearest (less than 0.5ulp error)
|
|
as long as the floating-point number is binary, and the integer type used by the rational number is unbounded.
|
|
|
|
Additional conversions may be supported by particular backends.
|
|
|
|
* A `number` can be converted to any built in type, via an explicit conversion operator:
|
|
this functionality is only available on compilers supporting C++11's explicit conversion syntax.
|
|
|
|
mpz_int z(2);
|
|
int i = z; // Error, implicit conversion not allowed.
|
|
int j = static_cast<int>(z); // OK explicit conversion.
|
|
|
|
* Any number type can be ['explicitly] constructed (or assigned) from a `const char*` or a `std::string`:
|
|
|
|
// pi to 50 places from a string:
|
|
cpp_dec_float_50 df("3.14159265358979323846264338327950288419716939937510");
|
|
// Integer type will automatically detect "0x" and "0" prefixes and parse the string accordingly:
|
|
cpp_int i("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000");
|
|
// Invalid input always results in a std::runtime_error being thrown:
|
|
i = static_cast<cpp_int>("3.14");
|
|
// implicit conversions from strings are not allowed:
|
|
i = "23"; // Error, no assignment operator for implicit conversion from string
|
|
// assign member function, avoids having to create a temporary via a static_cast:
|
|
i.assign("23"); // OK
|
|
|
|
* Any number type will interoperate with the builtin types in arithmetic expressions as long as the conversions
|
|
are not lossy:
|
|
|
|
// pi to 50 places from a string:
|
|
cpp_dec_float_50 df = "3.14159265358979323846264338327950288419716939937510";
|
|
// Multiply by 2 - using an integer literal here is usually more efficient
|
|
// than constructing a temporary:
|
|
df *= 2;
|
|
|
|
// You can't mix integer types with floats though:
|
|
cpp_int i = 2;
|
|
i *= 3.14; // Error, no *= operator will be found.
|
|
|
|
* Any number type can be streamed to and from the C++ iostreams:
|
|
|
|
cpp_dec_float_50 df = "3.14159265358979323846264338327950288419716939937510";
|
|
// Now print at full precision:
|
|
std::cout << std::setprecision(std::numeric_limits<cpp_dec_float_50>::max_digits10)
|
|
<< df << std::endl
|
|
cpp_int i = 1;
|
|
i <<= 256;
|
|
// Now print in hex format with prefix:
|
|
std::cout << std::hex << std::showbase << i << std::endl;
|
|
|
|
* Interconversions between number types of the same family are allowed and are implicit conversions if no
|
|
loss of precision is involved, and explicit if it is:
|
|
|
|
int128_t i128 = 0;
|
|
int266_t i256 = i128; // OK implicit widening conversion
|
|
i128_t = i256; // Error, no assignment operator found, narrowing conversion is explicit.
|
|
i128_t = static_cast<int128_t>(i256); // OK, explicit narrowing conversion.
|
|
|
|
mpz_int z = 0;
|
|
mpf_float f = z; // OK, GMP handles this conversion natively, and it's not lossy and therefore implicit.
|
|
|
|
mpf_float_50 f50 = 2;
|
|
f = f50; // OK, conversion from fixed to variable precision, f will have 50 digits precision.
|
|
f50 = f; // Error, conversion from variable to fixed precision is potentially lossy, explicit cast required.
|
|
|
|
* Some interconversions between number types are completely generic, and are always available, albeit the conversions are always ['explicit]:
|
|
|
|
cpp_int cppi(2);
|
|
// We can always convert between numbers of the same category -
|
|
// int to int, rational to rational, or float to float, so this is OK
|
|
// as long as we use an explicit conversion:
|
|
mpz_int z(cppi);
|
|
// We can always promote from int to rational, int to float, or rational to float:
|
|
cpp_rational cppr(cppi); // OK, int to rational
|
|
cpp_dec_float_50 df(cppi); // OK, int to float
|
|
df = static_cast<cpp_dec_float_50>(cppr); // OK, explicit rational to float conversion
|
|
// However narrowing and/or implicit conversions always fail:
|
|
cppi = df; // Compiler error, conversion not allowed
|
|
|
|
* Other interconversions may be allowed as special cases, whenever the backend allows it:
|
|
|
|
mpf_t m; // Native GMP type.
|
|
mpf_init_set_ui(m, 0); // set to a value;
|
|
mpf_float i(m); // copies the value of the native type.
|
|
|
|
More information on what additional types a backend supports conversions from are given in the tutorial for each backend.
|
|
The converting constructor will be implicit if the backend's converting constructor is also implicit, and explicit if the
|
|
backends converting constructor is also explicit.
|
|
|
|
[endsect]
|
|
|
|
[section:random Generating Random Numbers]
|
|
|
|
Random numbers are generated in conjunction with Boost.Random.
|
|
|
|
There is a single generator that supports generating random integers with large bit counts:
|
|
[@http://www.boost.org/doc/html/boost/random/independent_bits_engine.html `independent_bits_engine`].
|
|
This type can be used with either ['unbounded] integer types, or with ['bounded] (ie fixed precision) unsigned integers:
|
|
|
|
[random_eg1]
|
|
|
|
Program output is:
|
|
|
|
[random_eg1_out]
|
|
|
|
In addition, the generator adaptors [@http://www.boost.org/doc/html/boost/random/discard_block_engine.html `discard_block`],
|
|
[@http://www.boost.org/doc/html/boost/random/xor_combine_engine.html `xor_combine_engine`] and
|
|
[@http://www.boost.org/doc/html/boost/random/discrete_distribution.html `discrete_distribution`] can be used
|
|
with multiprecision types. Note that if you seed an `independent_bits_engine`, then you are actually seeding
|
|
the underlying generator, and should therefore provide a sequence of unsigned 32-bit values as the seed.
|
|
|
|
Alternatively we can generate integers in a given range using
|
|
[@http://www.boost.org/doc/html/boost/random/uniform_int_distribution.html `uniform_int_distribution`], this will
|
|
invoke the underlying engine multiple times to build up the required number of bits in the result:
|
|
|
|
[random_eg2]
|
|
|
|
[random_eg2_out]
|
|
|
|
It is also possible to use [@http://www.boost.org/doc/html/boost/random/uniform_int_distribution.html `uniform_int_distribution`]
|
|
with a multiprecision generator such as [@http://www.boost.org/doc/html/boost/random/independent_bits_engine.html `independent_bits_engine`].
|
|
Or to use [@http://www.boost.org/doc/html/boost/random/uniform_smallint.html `uniform_smallint`] or
|
|
[@http://www.boost.org/doc/html/boost/random/random_number_generator.html `random_number_generator`] with multiprecision types.
|
|
|
|
floating-point values in \[0,1) are most easily generated using [@http://www.boost.org/doc/html/boost/random/generate_canonical.html `generate_canonical`],
|
|
note that `generate_canonical` will call the generator multiple times to produce the requested number of bits, for example we can use
|
|
it with a regular generator like so:
|
|
|
|
[random_eg3]
|
|
|
|
[random_eg3_out]
|
|
|
|
Note however, the distributions do not invoke the generator multiple times to fill up the mantissa of a multiprecision floating-point type
|
|
with random bits. For these therefore, we should probably use a multiprecision generator (ie `independent_bits_engine`) in combination
|
|
with the distribution:
|
|
|
|
[random_eg4]
|
|
|
|
[random_eg4_out]
|
|
|
|
And finally, it is possible to use the floating-point generators [@http://www.boost.org/doc/html/boost/random/lagged_fibonacci_01_engine.html `lagged_fibonacci_01_engine`]
|
|
and [@http://www.boost.org/doc/html/boost/random/subtract_with_idp144360752.html `subtract_with_carry_01_engine`] directly with multiprecision floating-point types.
|
|
It's worth noting however, that there is a distinct lack of literature on generating high bit-count random numbers, and therefore a lack of "known good" parameters to
|
|
use with these generators in this situation. For this reason, these should probably be used for research purposes only:
|
|
|
|
[random_eg5]
|
|
|
|
[endsect]
|
|
|
|
[section:primetest Primality Testing]
|
|
|
|
The library implements a Miller-Rabin test for primality:
|
|
|
|
#include <boost/multiprecision/miller_rabin.hpp>
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates, class Engine>
|
|
bool miller_rabin_test(const number<Backend, ExpressionTemplates>& n, unsigned trials, Engine& gen);
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates, class Engine>
|
|
bool miller_rabin_test(const number<Backend, ExpressionTemplates>& n, unsigned trials);
|
|
|
|
These functions perform a Miller-Rabin test for primality, if the result is `false` then /n/ is definitely composite,
|
|
while if the result is true then n is probably prime. The probability to declare a composite n as probable prime is
|
|
at most 0.25[super trials]. Note that this does not allow a statement about the probability of n being actually
|
|
prime (for that, the prior probability would have to be known). The algorithm used performs some
|
|
trial divisions to exclude small prime factors, does one Fermat test to exclude many more composites, and then
|
|
uses the Miller-Rabin algorithm straight out of
|
|
Knuth Vol 2, which recommends 25 trials for a pretty strong likelihood that /n/ is prime.
|
|
|
|
The third optional argument is for a Uniform Random Number Generator from Boost.Random. When not provided the `mt19937`
|
|
generator is used. Note that when producing random primes then you should probably use a different random number generator
|
|
to produce candidate prime numbers for testing, than is used internally by `miller_rabin_test` for determining
|
|
whether the value is prime. It also helps of course to seed the generators with some source of randomness.
|
|
|
|
The following example searches for a prime `p` for which `(p-1)/2` is also probably prime:
|
|
|
|
[safe_prime]
|
|
|
|
[endsect]
|
|
|
|
[section:lits Literal Types and `constexpr` Support]
|
|
|
|
There are two kinds of `constexpr` support in this library:
|
|
|
|
* The more basic version requires only C++11 and allow the construction of some number types as literals.
|
|
* The more advanced support permits constexpr arithmetic and requires at least C++14
|
|
constexpr support, and for many operations C++2a support
|
|
|
|
[h4 Declaring numeric literals]
|
|
|
|
There are two backend types which are literals:
|
|
|
|
* __float128 (which requires GCC), and
|
|
* Instantiations of `cpp_int_backend` where the Allocator parameter is type `void`.
|
|
In addition, prior to C++14 the Checked parameter must be `boost::multiprecision::unchecked`.
|
|
|
|
For example:
|
|
|
|
using namespace boost::multiprecision;
|
|
|
|
constexpr float128 f = 0.1Q // OK, float128's are always literals in C++11
|
|
|
|
constexpr int128_t i = 0; // OK, fixed precision int128_t has no allocator.
|
|
constexpr uint1024_t j = 0xFFFFFFFF00000000uLL; // OK, fixed precision uint1024_t has no allocator.
|
|
|
|
constexpr checked_uint128_t k = 1; // OK from C++14 and later, not supported for C++11.
|
|
constexpr checked_uint128_t k = -1; // Error, as this would normally lead to a runtime failure (exception).
|
|
constexpr cpp_int l = 2; // Error, type is not a literal as it performs memory management.
|
|
|
|
There is also support for user defined-literals with __cpp_int - these are limited to unchecked, fixed precision `cpp_int`'s
|
|
which are specified in hexadecimal notation. The suffixes supported are:
|
|
|
|
[table
|
|
[[Suffix][Meaning]]
|
|
[[_cppi][Specifies a value of type: `number<cpp_int_backend<N,N,signed_magnitude,unchecked,void> >`, where N is chosen
|
|
to contain just enough digits to hold the number specified.]]
|
|
[[_cppui][Specifies a value of type: `number<cpp_int_backend<N,N,unsigned_magnitude,unchecked,void> >`, where N is chosen
|
|
to contain just enough digits to hold the number specified.]]
|
|
[[_cppi['N]][Specifies a value of type `number<cpp_int_backend<N,N,signed_magnitude,unchecked,void> >`.]]
|
|
[[_cppui['N]][Specifies a value of type `number<cpp_int_backend<N,N,signed_magnitude,unchecked,void> >`.]]
|
|
]
|
|
|
|
In each case, use of these suffixes with hexadecimal values produces a `constexpr` result.
|
|
|
|
Examples:
|
|
|
|
//
|
|
// Any use of user defined literals requires that we import the literal-operators
|
|
// into current scope first:
|
|
using namespace boost::multiprecision::literals;
|
|
//
|
|
// To keep things simple in the example, we'll make our types used visible to this scope as well:
|
|
using namespace boost::multiprecision;
|
|
//
|
|
// The value zero as a number<cpp_int_backend<4,4,signed_magnitude,unchecked,void> >:
|
|
constexpr auto a = 0x0_cppi;
|
|
// The type of each constant has 4 bits per hexadecimal digit,
|
|
// so this is of type uint256_t (ie number<cpp_int_backend<256,256,unsigned_magnitude,unchecked,void> >):
|
|
constexpr auto b = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cppui;
|
|
//
|
|
// Smaller values can be assigned to larger values:
|
|
int256_t c = 0x1234_cppi; // OK
|
|
//
|
|
// However, this only works in constexpr contexts from C++14 onwards:
|
|
constexpr int256_t d = 0x1_cppi; // Compiler error in C++11, requires C++14
|
|
//
|
|
// Constants can be padded out with leading zeros to generate wider types:
|
|
constexpr uint256_t e = 0x0000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFF_cppui; // OK
|
|
//
|
|
// However, specific width types are best produced with specific-width suffixes,
|
|
// ones supported by default are `_cpp[u]i128`, `_cpp[u]i256`, `_cpp[u]i512`, `_cpp[u]i1024`.
|
|
//
|
|
constexpr int128_t f = 0x1234_cppi128; // OK, always produces an int128_t as the result.
|
|
constexpr uint1024_t g = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccc_cppui1024;
|
|
//
|
|
// If other specific width types are required, then there is a macro for generating the operators
|
|
// for these. The macro can be used at namespace scope only:
|
|
//
|
|
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(2048);
|
|
//
|
|
// Now we can create 2048-bit literals as well:
|
|
constexpr auto h = 0xff_cppi2048; // h is of type number<cpp_int_backend<2048,2048,signed_magnitude,unchecked,void> >
|
|
//
|
|
// Finally negative values are handled via the unary minus operator:
|
|
//
|
|
constexpr int1024_t i = -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cppui1024;
|
|
//
|
|
// Which means this also works:
|
|
constexpr int1024_t j = -g; // OK: unary minus operator is constexpr.
|
|
|
|
[h4 constexpr arithmetic]
|
|
|
|
The front end of the library is all `constexpr` from C++14 and later. Currently there are only two
|
|
back end types that are `constexpr` aware: __float128 and __cpp_int. More backends will follow at a later date.
|
|
|
|
Provided the compiler is GCC, type __float128 support `constexpr` operations on all arithmetic operations from C++14, comparisons,
|
|
`abs`, `fabs`, `fpclassify`, `isnan`, `isinf`, `isfinite` and `isnormal` are also fully supported, but the transcendental functions are not.
|
|
|
|
The __cpp_int types support constexpr arithmetic, provided it is a fixed precision type with no allocator. It may also
|
|
be a checked integer: in which case a compiler error will be generated on overflow or undefined behaviour. In addition
|
|
the free functions `abs`, `swap`, `multiply`, `add`, `subtract`, `divide_qr`, `integer_modulus`, `powm`, `lsb`, `msb`,
|
|
`bit_test`, `bit_set`, `bit_unset`, `bit_flip`, `sqrt`, `gcd`, `lcm` are all supported. Use of __cpp_int in this way
|
|
requires either a C++2a compiler (one which supports `std::is_constant_evaluated()` - currently only gcc-9 or clang-9 or later),
|
|
or GCC-6 or later in C++14 mode.
|
|
Compilers other than GCC and without `std::is_constant_evaluated()` will support a very limited set of operations:
|
|
expect to hit roadblocks rather easily.
|
|
|
|
For example given:
|
|
|
|
[constexpr_circle]
|
|
|
|
We can now calculate areas and circumferences using all constexpr arithmetic:
|
|
|
|
[constexpr_circle_usage]
|
|
|
|
Note that these make use of the numeric constants from the Math library, which also happen to be `constexpr`.
|
|
|
|
For a more interesting example, in [@../../example/constexpr_float_arithmetic_examples.cpp constexpr_float_arithmetic_examples.cpp]
|
|
we define a simple class for `constexpr` polynomial arithmetic:
|
|
|
|
template <class T, unsigned Order>
|
|
struct const_polynomial;
|
|
|
|
Given this, we can use recurrence relations to calculate the coefficients for various orthogonal
|
|
polynomials - in the example we use the Hermite polynomials, only the constructor does any work -
|
|
it uses the recurrence relations to calculate the coefficient array:
|
|
|
|
[hermite_example]
|
|
|
|
Now we just need to define H[sub 0] and H[sub 1] as termination conditions for the recurrence:
|
|
|
|
[hermite_example2]
|
|
|
|
We can now declare H[sub 9] as a constexpr object, access the coefficients, and evaluate
|
|
at an abscissa value, all using `constexpr` arithmetic:
|
|
|
|
[hermite_example3]
|
|
|
|
Also since the coefficients to the Hermite polynomials are integers, we can also generate the Hermite
|
|
coefficients using (fixed precision) cpp_int's: see [@../../test/constexpr_test_cpp_int_6.cpp constexpr_test_cpp_int_6.cpp].
|
|
|
|
We can also generate factorials (and validate the result) like so:
|
|
|
|
[factorial_decl]
|
|
|
|
constexpr uint1024_t f1 = factorial(uint1024_t(31));
|
|
static_assert(f1 == 0x1956ad0aae33a4560c5cd2c000000_cppi);
|
|
|
|
Another example in [@../../test/constexpr_test_cpp_int_7.cpp constexpr_test_cpp_int_7.cpp] generates
|
|
a fresh multiprecision random number each time the file is compiled.
|
|
|
|
|
|
[endsect]
|
|
|
|
[section:import_export Importing and Exporting Data to and from `cpp_int` and `cpp_bin_float`]
|
|
|
|
Any integer number type that uses `cpp_int_backend` as it's implementation layer can import or export its bits via two non-member functions:
|
|
|
|
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
|
|
expression_template_option ExpressionTemplates, class OutputIterator>
|
|
OutputIterator export_bits(
|
|
const number<const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
|
|
OutputIterator out,
|
|
unsigned chunk_size,
|
|
bool msv_first = true);
|
|
|
|
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
|
|
expression_template_option ExpressionTemplates, class Iterator>
|
|
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
|
import_bits(
|
|
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
|
|
Iterator i,
|
|
Iterator j,
|
|
unsigned chunk_size = 0,
|
|
bool msv_first = true);
|
|
|
|
These functions are designed for data-interchange with other storage formats, and since __cpp_bin_float uses __cpp_int internally,
|
|
by extension they can be used for floating-point numbers based on that backend as well (see example below).
|
|
Parameters and use are as follows:
|
|
|
|
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
|
|
expression_template_option ExpressionTemplates, class OutputIterator>
|
|
OutputIterator export_bits(
|
|
const number<const cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
|
|
OutputIterator out,
|
|
unsigned chunk_size,
|
|
bool msv_first = true);
|
|
|
|
Exports the absolute value of `val` to OutputIterator `out`. The function will write `chunk_size` bits at a time
|
|
to the OutputIterator, and if `msv_first` is true, will write the most-significant block first. Byte and bit order
|
|
within each `chunk_size` block is always in the machines native format. Further, each block is stored in a
|
|
`boost::uintmax_t` when it's assigned to `*out`.
|
|
|
|
[note Unfortunately, the standard's OutputIterator concept provides no means of deducing the type to output since
|
|
`std::iterator_traits<OutputIteratorType>::value_type` is type `void`. This is why the bit count for each block
|
|
has to be specified manually. It may also result in compiler warnings about the value being narrowed.]
|
|
|
|
[tip If you're exporting to non-native byte layout, then use
|
|
[@http://www.boost.org/doc/libs/release/libs/endian/doc/index.html Boost.Endian]
|
|
to create a custom OutputIterator that reverses the byte order of each chunk prior to actually storing the result.]
|
|
|
|
template <unsigned MinBits, unsigned MaxBits, cpp_integer_type SignType, cpp_int_check_type Checked, class Allocator,
|
|
expression_template_option ExpressionTemplates, class ForwardIterator>
|
|
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>&
|
|
import_bits(
|
|
number<cpp_int_backend<MinBits, MaxBits, SignType, Checked, Allocator>, ExpressionTemplates>& val,
|
|
ForwardIterator i,
|
|
ForwardIterator j,
|
|
unsigned chunk_size = 0,
|
|
bool msv_first = true);
|
|
|
|
Imports bits from the iterator range ['\[i,j)] and stores them in `val` to produce an unsigned result (if the result
|
|
is to be signed you will need to handle that separately). When `msv_first` is true, takes `*i` as the most significant
|
|
chunk. Assumes there are `chunk_size` bits in each value read from the iterator range, and that these are in machine native
|
|
bit/byte order. When `chunk_size` is zero, then assumes that each chunk contains
|
|
`std::numeric_limits<std::iterator_traits<ForwardIterator>::value_type>::digits`, note that this will give the wrong result
|
|
if dereferencing the iterators leads to a signed-integer type, [*and] the sign bit is significant (be particularly careful
|
|
if you expect type `char` to contain 8-bit values, as by default it will extract only 7-bits at a time if `char` is signed).
|
|
As with exporting, if the external data is to be in a non-native byte order (within each chunk), then you will need to create an iterator adaptor
|
|
that presents it in native order (see [@http://www.boost.org/doc/libs/release/libs/endian/doc/index.html Boost.Endian]).
|
|
|
|
[note
|
|
Note that this function is optimized for the case where the data can be `memcpy`ed from the source to the integer - in this case both
|
|
iterators much be pointers, and everything must be little-endian.]
|
|
|
|
[h4 Examples]
|
|
|
|
[IE1]
|
|
|
|
[IE2]
|
|
|
|
[endsect] [/section:import_export Importing and Exporting Data to and from `cpp_int` and `cpp_bin_float`]
|
|
|
|
[section:rounding Rounding Rules for Conversions]
|
|
|
|
As a general rule, all conversions between unrelated types are performed using basic arithmetic operations, therefore
|
|
conversions are either exact, or follow the same rounding rules as arithmetic for the type in question.
|
|
|
|
The following table summarises the situation for conversions from native types:
|
|
|
|
[table
|
|
[[Backend][Rounding Rules]]
|
|
[[__cpp_int][Conversions from integer types are exact if the target has sufficient precision, otherwise they
|
|
truncate to the first 2^MaxBits bits (modulo arithmetic). Conversions from floating-point types
|
|
are truncating to the nearest integer.]]
|
|
[[__gmp_int][Conversions are performed by the GMP library except for conversion from `long double` which is truncating.]]
|
|
[[__tom_int][Conversions from floating-point types are truncating, all others are performed by libtommath and are exact.]]
|
|
[[__gmp_float][Conversions are performed by the GMP library except for conversion from `long double` which should be exact
|
|
provided the target type has as much precision as a `long double`.]]
|
|
[[__mpfr_float_backend][All conversions are performed by the underlying MPFR library.]]
|
|
[[__cpp_dec_float][All conversions are performed using basic arithmetic operations and are truncating.]]
|
|
[[__gmp_rational][See __gmp_int]]
|
|
[[__cpp_rational][See __cpp_int]]
|
|
[[__tommath_rational][See __tom_int]]
|
|
]
|
|
|
|
[endsect] [/section:rounding Rounding Rules for Conversions]
|
|
|
|
[section:mixed Mixed Precision Arithmetic]
|
|
|
|
Mixed precision arithmetic is fully supported by the library.
|
|
|
|
There are two different forms:
|
|
|
|
* Where the operands are of different precision.
|
|
* Where the operands are of the same precision, but yield a higher precision result.
|
|
|
|
[h4 Mixing Operands of Differing Precision]
|
|
|
|
If the arguments to a binary operator are of different precision, then the operation is allowed
|
|
as long as there is an unambiguous implicit conversion from one argument type to the other.
|
|
In all cases the arithmetic is performed "as if" the lower precision type is promoted to the
|
|
higher precision type before applying the operator. However, particular backends may optimise
|
|
this and avoid actually creating a temporary if they are able to do so.
|
|
|
|
For example:
|
|
|
|
mpfr_float_50 a(2), b;
|
|
mpfr_float_100 c(3), d;
|
|
static_mpfr_float_50 e(5), f;
|
|
mpz_int i(20);
|
|
|
|
d = a * c; // OK, result of operand is an mpfr_float_100.
|
|
b = a * c; // Error, can't convert the result to an mpfr_float_50 as it will lose digits.
|
|
f = a * e; // Error, operator is ambiguous, result could be of either type.
|
|
f = e * i; // OK, unambiguous conversion from mpz_int to static_mpfr_float_50
|
|
|
|
[h4 Operands of the Same Precision]
|
|
|
|
Sometimes you want to apply an operator to two arguments of the same precision in
|
|
such a way as to obtain a result of higher precision. The most common situation
|
|
occurs with fixed precision integers, where you want to multiply two N-bit numbers
|
|
to obtain a 2N-bit result. This is supported in this library by the following
|
|
free functions:
|
|
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& add(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& subtract(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& multiply(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
These functions apply the named operator to the arguments ['a] and ['b] and store the
|
|
result in ['result], returning ['result]. In all cases they behave "as if"
|
|
arguments ['a] and ['b] were first promoted to type `ResultType` before applying the
|
|
operator, though particular backends may well avoid that step by way of an optimization.
|
|
|
|
The type `ResultType` must be an instance of class `number`, and the types `Source1` and `Source2`
|
|
may be either instances of class `number` or native integer types. The latter is an optimization
|
|
that allows arithmetic to be performed on native integer types producing an extended precision result.
|
|
|
|
For example:
|
|
|
|
[mixed_eg]
|
|
|
|
Produces the output:
|
|
|
|
[mixed_output]
|
|
|
|
[h4 Backends With Optimized Mixed Precision Arithmetic]
|
|
|
|
The following backends have at least some direct support for mixed precision arithmetic,
|
|
and therefore avoid creating unnecessary temporaries when using the interfaces above.
|
|
Therefore when using these types it's more efficient to use mixed precision arithmetic,
|
|
than it is to explicitly cast the operands to the result type:
|
|
|
|
__mpfr_float_backend, __mpf_float, __cpp_int.
|
|
|
|
[endsect] [/section:mixed Mixed Precision Arithmetic]
|
|
|
|
[section:gen_int Generic Integer Operations]
|
|
|
|
All of the [link boost_multiprecision.ref.number.integer_functions non-member integer operations] are overloaded for the
|
|
built in integer types in
|
|
`<boost/multiprecision/integer.hpp>`.
|
|
Where these operations require a temporary increase in precision (such as for `powm`), then
|
|
if no built in type is available, a __cpp_int of appropriate precision will be used.
|
|
|
|
Some of these functions are trivial, others use compiler intrinsics (where available) to ensure optimal evaluation.
|
|
|
|
The overloaded functions are:
|
|
|
|
template <class Integer, class I2>
|
|
Integer& multiply(Integer& result, const I2& a, const I2& b);
|
|
|
|
Multiplies two `I2` values, to produce a wider `Integer` result.
|
|
|
|
Returns `result = a * b` without overflow or loss of precision in the multiplication.
|
|
|
|
template <class Integer, class I2>
|
|
Integer& add(Integer& result, const I2& a, const I2& b);
|
|
|
|
Adds two `I2` values, to produce a wider `Integer` result.
|
|
|
|
Returns `result = a + b` without overflow or loss of precision in the addition.
|
|
|
|
template <class Integer, class I2>
|
|
Integer& subtract(Integer& result, const I2& a, const I2& b);
|
|
|
|
Subtracts two `I2` values, to produce a wider `Integer` result.
|
|
|
|
Returns `result = a - b` without overflow or loss of precision in the subtraction.
|
|
|
|
template <class Integer>
|
|
Integer powm(const Integer& b, const Integer& p, const Integer& m);
|
|
|
|
Returns b[super p] % m.
|
|
|
|
template <class Integer>
|
|
void divide_qr(const Integer& x, const Integer& y, Integer& q, Integer& r);
|
|
|
|
Sets `q = x / y` and `r = x % y`.
|
|
|
|
template <class Integer1, class Integer2>
|
|
Integer2 integer_modulus(const Integer1& x, Integer2 val);
|
|
|
|
Returns x % val;
|
|
|
|
template <class Integer>
|
|
unsigned lsb(const Integer& x);
|
|
|
|
Returns the (zero-based) index of the least significant bit of `x`.
|
|
|
|
Throws a `std::domain_error` if `x <= 0`.
|
|
|
|
template <class Integer>
|
|
unsigned msb(const Integer& x);
|
|
|
|
Returns the (zero-based) index of the most significant bit of `x`.
|
|
|
|
Throws a `std::domain_error` if `x <= 0`.
|
|
|
|
template <class Integer>
|
|
bool bit_test(const Integer& val, unsigned index);
|
|
|
|
Returns `true` if bit `index` is set in `val`.
|
|
|
|
template <class Integer>
|
|
Integer& bit_set(Integer& val, unsigned index);
|
|
|
|
Sets the `index` bit in `val`.
|
|
|
|
template <class Integer>
|
|
Integer& bit_unset(Integer& val, unsigned index);
|
|
|
|
Unsets the `index` bit in `val`.
|
|
|
|
template <class Integer>
|
|
Integer& bit_flip(Integer& val, unsigned index);
|
|
|
|
Flips the `index` bit in `val`.
|
|
|
|
template <class Integer>
|
|
Integer sqrt(const Integer& x);
|
|
template <class Integer>
|
|
Integer sqrt(const Integer& x, Integer& r);
|
|
|
|
Returns the integer square root `s` of x and sets `r` to the remainder ['x - s[super 2]].
|
|
|
|
template <class Engine>
|
|
bool miller_rabin_test(const number-or-expression-template-type& n, unsigned trials, Engine& gen);
|
|
bool miller_rabin_test(const number-or-expression-template-type& n, unsigned trials);
|
|
|
|
The regular Miller-Rabin functions in `<boost/multiprecision/miller_rabin.hpp>` are defined in terms of the above
|
|
generic operations, and so function equally well for built-in or __fundamental_types and multiprecision types.
|
|
|
|
[endsect] [/section:gen_int Generic Integer Operations]
|
|
|
|
[section:serial Boost.Serialization Support]
|
|
|
|
Support for serialization comes in two forms:
|
|
|
|
* Classes __number, __debug_adaptor, __logged_adaptor and __rational_adaptor have "pass through" serialization
|
|
support which requires the underlying backend to be serializable.
|
|
* Backends __cpp_int, __cpp_bin_float, __cpp_dec_float and __float128 have full support for Boost.Serialization.
|
|
|
|
[endsect] [/section:serialization Boost Serialization]
|
|
|
|
[section:limits Numeric Limits]
|
|
|
|
Boost.Multiprecision tries hard to implement `std::numeric_limits` for all types
|
|
as far as possible and meaningful because experience with Boost.Math has shown that this aids portability.
|
|
|
|
The [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf C++ standard library]
|
|
defines `std::numeric_limits` in section 18.3.2.
|
|
|
|
This in turn refers to the C standard
|
|
[@http://www.open-std.org/jtc1/sc22/wg11/docs/n507.pdf SC22/WG11 N507 DRAFT INTERNATIONAL ISO/IEC STANDARD
|
|
WD 10967-1]
|
|
Information technology Language independent arithmetic Part 1: Integer and floating-point arithmetic.
|
|
|
|
That C Standard in turn refers to
|
|
|
|
[@https://doi.org/10.1109/IEEESTD.1985.82928 IEEE754 IEEE Standard for Binary
|
|
Floating-Point Arithmetic]
|
|
|
|
There is a useful summary at
|
|
[@http://www.cplusplus.com/reference/limits/numeric_limits/ C++ reference].
|
|
|
|
The chosen backend often determines how completely `std::numeric_limits` is available.
|
|
|
|
Compiler options, processor type, and definition of macros or assembler instructions to control denormal numbers will alter
|
|
the values in the tables given below.
|
|
|
|
[warning GMP's `mpf_t` does not have a concept of overflow:
|
|
operations that lead to overflow eventually run of out of resources
|
|
and terminate with stack overflow (often after several seconds).]
|
|
|
|
[section:constants std::numeric_limits<> constants]
|
|
|
|
[h4 is_specialized]
|
|
|
|
`true` for all arithmetic types (integer, floating and fixed-point)
|
|
for which `std::numeric_limits<T>::numeric_limits` is specialized.
|
|
|
|
A typical test is
|
|
|
|
if (std::numeric_limits<T>::is_specialized == false)
|
|
{
|
|
std::cout << "type " << typeid(T).name() << " is not specialized for std::numeric_limits!" << std::endl;
|
|
// ...
|
|
}
|
|
|
|
Typically `numeric_limits<T>::is_specialized` is `true` for all `T` where the compile-time constant
|
|
members of `numeric_limits` are indeed known at compile time, and don't vary at runtime. For example
|
|
floating-point types with runtime-variable precision such as `mpfr_float` have no `numeric_limits`
|
|
specialization as it would be impossible to define all the members at compile time. In contrast
|
|
the precision of a type such as `mpfr_float_50` is known at compile time, and so it ['does] have a
|
|
`numeric_limits` specialization.
|
|
|
|
Note that not all the `std::numeric_limits` member constants and functions are meaningful for all user-defined types (UDT),
|
|
such as the decimal and binary multiprecision types provided here. More information on this is given in the sections below.
|
|
|
|
[h4 infinity]
|
|
|
|
For floating-point types, [infin] is defined wherever possible,
|
|
but clearly infinity is meaningless for __arbitrary_precision arithmetic backends,
|
|
and there is one floating-point type (GMP's `mpf_t`, see __mpf_float) which has no notion
|
|
of infinity or NaN at all.
|
|
|
|
A typical test whether infinity is implemented is
|
|
|
|
if(std::numeric_limits<T>::has_infinity)
|
|
{
|
|
std::cout << std::numeric_limits<T>::infinity() << std::endl;
|
|
}
|
|
|
|
and using tests like this is strongly recommended to improve portability.
|
|
|
|
If the backend is switched to a type that does not support infinity then,
|
|
without checks like this, there will be trouble.
|
|
|
|
[h4 is_signed]
|
|
|
|
`std::numeric_limits<T>::is_signed == true` if the type `T` is signed.
|
|
|
|
For built-in binary types, the sign is held in a single bit,
|
|
but for other types (cpp_dec_float and cpp_bin_float)
|
|
it may be a separate storage element, usually `bool`.
|
|
|
|
[h4 is_exact]
|
|
|
|
`std::numeric_limits<T>::is_exact == true` if type T uses exact representations.
|
|
|
|
This is defined as `true` for all integer types and `false` for floating-point types.
|
|
|
|
[@http://stackoverflow.com/questions/14203654/stdnumeric-limitsis-exact-what-is-a-usable-definition A usable definition]
|
|
has been discussed.
|
|
|
|
ISO/IEC 10967-1, Language independent arithmetic, noted by the C++ Standard defines
|
|
|
|
A floating-point type F shall be a finite subset of [real].
|
|
|
|
The important practical distinction is that all integers (up to `max()`) can be stored exactly.
|
|
|
|
[@http://en.wikipedia.org/wiki/Rational_number Rational]
|
|
types using two integer types are also exact.
|
|
|
|
Floating-point types [*cannot store all real values]
|
|
(those in the set of [real]) [*exactly].
|
|
For example, 0.5 can be stored exactly in a binary floating-point, but 0.1 cannot.
|
|
What is stored is the nearest representable real value, that is, rounded to nearest.
|
|
|
|
Fixed-point types (usually decimal) are also defined as exact, in that they only
|
|
store a [*fixed precision], so half cents or pennies (or less) cannot be stored.
|
|
The results of computations are rounded up or down,
|
|
just like the result of integer division stored as an integer result.
|
|
|
|
There are number of proposals to
|
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3407.html
|
|
add Decimal floating-point Support to C++].
|
|
|
|
[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2849.pdf Decimal TR].
|
|
|
|
And also
|
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html
|
|
C++ Binary Fixed-Point Arithmetic].
|
|
|
|
[h4 is_bounded]
|
|
|
|
`std::numeric_limits<T>::is_bounded == true` if the set of values represented by the type `T` is finite.
|
|
|
|
This is `true` for all built-in integer, fixed and floating-point types,
|
|
and most multi-precision types.
|
|
|
|
It is only `false` for a few __arbitrary_precision types like `cpp_int`.
|
|
|
|
Rational and fixed-exponent representations are exact but not integer.
|
|
|
|
[h4 is_modulo]
|
|
|
|
`std::numeric_limits<T>::is_modulo` is defined as `true` if adding two positive values of type T
|
|
can yield a result less than either value.
|
|
|
|
`is_modulo == true` means that the type does not overflow, but, for example,
|
|
'wraps around' to zero, when adding one to the `max()` value.
|
|
|
|
For most built-in integer types, `std::numeric_limits<>::is_modulo` is `true`.
|
|
|
|
`bool` is the only exception.
|
|
|
|
The modulo behaviour is sometimes useful,
|
|
but also can be unexpected, and sometimes undesired, behaviour.
|
|
|
|
Overflow of signed integers can be especially unexpected,
|
|
possibly causing change of sign.
|
|
|
|
Boost.Multiprecision integer type `cpp_int` is not modulo
|
|
because as an __arbitrary_precision types,
|
|
it expands to hold any value that the machine resources permit.
|
|
|
|
However fixed precision __cpp_int's may be modulo if they are unchecked
|
|
(i.e. they behave just like built in integers), but not if they are checked
|
|
(overflow causes an exception to be raised).
|
|
|
|
Built-in and multi-precision floating-point types are normally not modulo.
|
|
|
|
Where possible, overflow is to `std::numeric_limits<>::infinity()`,
|
|
provided `std::numeric_limits<>::has_infinity == true`.
|
|
|
|
[h4 radix]
|
|
|
|
Constant `std::numeric_limits<T>::radix` returns either 2 (for built-in and binary types)
|
|
or 10 (for decimal types).
|
|
|
|
[h4 digits]
|
|
|
|
The number of `radix` digits that be represented without change:
|
|
|
|
* for integer types, the number of [*non-sign bits] in the significand.
|
|
* for floating types, the number of [*radix digits] in the significand.
|
|
|
|
The values include any implicit bit, so for example, for the ubiquious
|
|
`double` using 64 bits
|
|
([@http://en.wikipedia.org/wiki/Double_precision_floating-point_format IEEE binary64 ]),
|
|
`digits` == 53, even though there are only 52 actual bits of the significand stored in the representation.
|
|
The value of `digits` reflects the fact that there is one implicit bit which is always set to 1.
|
|
|
|
The Boost.Multiprecision binary types do not use an implicit bit, so the
|
|
`digits` member reflects exactly how many bits of precision were requested:
|
|
|
|
typedef number<cpp_bin_float<53, digit_base_2> > float64;
|
|
typedef number<cpp_bin_float<113, digit_base_2> > float128;
|
|
std::numeric_limits<float64>::digits == 53.
|
|
std::numeric_limits<float128>::digits == 113.
|
|
|
|
For the most common case of `radix == 2`,
|
|
`std::numeric_limits<T>::digits` is the number of bits in the representation,
|
|
not counting any sign bit.
|
|
|
|
For a decimal integer type, when `radix == 10`, it is the number of decimal digits.
|
|
|
|
[h4 digits10]
|
|
|
|
Constant `std::numeric_limits<T>::digits10` returns the number of
|
|
decimal digits that can be represented without change or loss.
|
|
|
|
For example, `numeric_limits<unsigned char>::digits10` is 2.
|
|
|
|
This somewhat inscrutable definition means that an `unsigned char`
|
|
can hold decimal values `0..99`
|
|
without loss of precision or accuracy, usually from truncation.
|
|
|
|
Had the definition been 3 then that would imply it could hold 0..999,
|
|
but as we all know, an 8-bit `unsigned char` can only hold 0..255,
|
|
and an attempt to store 256 or more will involve loss or change.
|
|
|
|
For bounded integers, it is thus [*one less] than number of decimal digits
|
|
you need to display the biggest integer `std::numeric_limits<T>::max()`.
|
|
This value can be used to predict the layout width required for
|
|
|
|
[digits10_1]
|
|
|
|
For example, `unsigned short` is often stored in 16 bits,
|
|
so the maximum value is 0xFFFF or 65535.
|
|
|
|
[digits10_2]
|
|
|
|
|
|
For bounded floating-point types,
|
|
if we create a `double` with a value with `digits10` (usually 15) decimal digits,
|
|
`1e15` or `1000000000000000` :
|
|
|
|
[digits10_3]
|
|
|
|
and we can increment this value to `1000000000000001`
|
|
as expected and show the difference too.
|
|
|
|
But if we try to repeat this with more than `digits10` digits,
|
|
|
|
[digits10_4]
|
|
|
|
then we find that when we add one it has no effect,
|
|
and display show that there is loss of precision. See
|
|
[@http://en.wikipedia.org/wiki/Loss_of_significance Loss of significance or cancellation error].
|
|
|
|
So `digits10` is the number of decimal digits [*guaranteed] to be correct.
|
|
|
|
For example, 'round-tripping' for `double`:
|
|
|
|
* If a decimal string with at most `digits10`( == 15) significant decimal digits
|
|
is converted to `double` and then converted back to the
|
|
same number of significant decimal digits,
|
|
then the final string will match the original 15 decimal digit string.
|
|
* If a `double` floating-point number is converted to a decimal string
|
|
with at least 17 decimal digits
|
|
and then converted back to `double`,
|
|
then the result will be binary identical to the original `double` value.
|
|
|
|
For most purposes, you will much more likely want
|
|
`std::numeric_limits<>::max_digits10`,
|
|
the number of decimal digits that ensure that a change of one least significant bit (ULP)
|
|
produces a different decimal digits string.
|
|
|
|
For the most common `double` floating-point type,`max_digits10` is `digits10+2`,
|
|
but you should use C++11 `max_digits10`
|
|
where possible (see [link boost_multiprecision.tut.limits.constants.max_digits10 below]).
|
|
|
|
[h4:max_digits10 max_digits10]
|
|
|
|
`std::numeric_limits<T>::max_digits10` was added for floating-point
|
|
because `digits10` decimal digits are insufficient to show
|
|
a least significant bit (ULP) change giving puzzling displays like
|
|
|
|
0.666666666666667 != 0.666666666666667
|
|
|
|
from failure to 'round-trip', for example:
|
|
|
|
[max_digits10_2]
|
|
|
|
If you wish to ensure that a change of one least significant bit (ULP)
|
|
produces a different decimal digits string,
|
|
then `max_digits10` is the precision to use.
|
|
|
|
For example:
|
|
|
|
[max_digits10_3]
|
|
|
|
will display [pi] to the maximum possible precision using a `double`.
|
|
|
|
[max_digits10_4]
|
|
|
|
For integer types, `max_digits10` is implementation-dependent,
|
|
but is usually `digits10 + 2`.
|
|
This is the output field-width required for the maximum value of the type T
|
|
`std::numeric_limits<T>::max()` ['including a sign and a space].
|
|
|
|
So this will produce neat columns.
|
|
|
|
std::cout << std::setw(std::numeric_limits<int>::max_digits10) ...
|
|
|
|
The extra two or three least-significant digits are 'noisy' and may be junk,
|
|
but if you want to 'round-trip' - printing a value out as a decimal digit string and reading it back in -
|
|
(most commonly during serialization and de-serialization)
|
|
you must use `os.precision(std::numeric_limits<T>::max_digits10)`.
|
|
|
|
[note For Microsoft Visual Studio 2010,
|
|
`std::numeric_limits<float>::max_digits10` is wrongly defined as 8. It should be 9.
|
|
]
|
|
|
|
[note For Microsoft Visual Studio before 2013 and the default floating-point
|
|
format, a small range of double-precision floating-point values with a
|
|
significand of approximately 0.0001 to 0.004 and exponent values of 1010 to
|
|
1014 do not round-trip exactly being off by one least significant bit,
|
|
for probably every third value of the significand.
|
|
|
|
A workaround is using the scientific or exponential format `std::scientific`.
|
|
|
|
Other compilers also fail to implement round-tripping entirely fault-free, for example, see
|
|
[@https://www.exploringbinary.com/incorrectly-rounded-conversions-in-gcc-and-glibc/ Incorrectly Rounded Conversions in GCC and GLIBC].
|
|
|
|
For more details see
|
|
[@https://www.exploringbinary.com/incorrect-round-trip-conversions-in-visual-c-plus-plus/ Incorrect Round-Trip Conversions in Visual C++],
|
|
and references therein
|
|
and
|
|
[@https://arxiv.org/pdf/1310.8121.pdf Easy Accurate Reading and Writing of Floating-Point Numbers, Aubrey Jaffer (August 2018)].
|
|
|
|
Microsoft VS2017 and other recent compilers, now use the
|
|
[@https://doi.org/10.1145/3192366.3192369 Ryu fast float-to-string conversion by Ulf Adams]
|
|
algorithm, claimed to be both exact and fast for 32 and 64-bit floating-point numbers.
|
|
] [/note]
|
|
|
|
[note BOOST_NO_CXX11_NUMERIC_LIMITS is a suitable feature-test macro to determine if
|
|
`std::numeric_limits<float>::max_digits10` is implemented on any platform.
|
|
] [/note]
|
|
|
|
[note ['requires cxx11_numeric_limits] is a suitable test for use of `std::numeric_limits<float>::max_digits10`
|
|
to control if a target in a jamfile used by a Boost B2/bjam program is built, or not.
|
|
] [/note]
|
|
|
|
|
|
If `max_digits10` is not available, you should use the
|
|
[@http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF Kahan formula for floating-point type T].
|
|
|
|
In C++, the equations for what Kahan (on page 4) describes as 'at least' and 'at most' are:
|
|
|
|
static long double const log10Two = 0.30102999566398119521373889472449L; // log10(2.)
|
|
|
|
static_cast<int>(floor((significand_digits - 1) * log10Two)); // == digits10 - 'at least' .
|
|
static_cast<int>(ceil(1 + significand_digits * log10Two)); // == max_digits10 - 'at most'.
|
|
|
|
Unfortunately, these cannot be evaluated (at least by C++03) at [*compile-time].
|
|
So the following expression is often used instead.
|
|
|
|
max_digits10 = 2 + std::numeric_limits<T>::digits * 3010U/10000U;
|
|
|
|
// == 2 + std::numeric_limits<T>::digits for double and 64-bit long double.
|
|
// == 3 + std::numeric_limits<T>::digits for float, 80-bit long-double and __float128.
|
|
|
|
often the actual values are computed for the C limits macros:
|
|
|
|
#define FLT_MAXDIG10 (2+FLT_MANT_DIG * 3010U/10000U) // 9
|
|
#define DBL_MAXDIG10 (2+ (DBL_MANT_DIG * 3010U)/10000U) // 17
|
|
#define LDBL_MAXDIG10 (2+ (LDBL_MANT_DIG * 3010U)/10000U) // 17 for MSVC, 18 for others.
|
|
|
|
The factor 3010U/10000U is ['log[sub 10](2) = 0.3010]
|
|
that can be evaluated at compile-time using only `short unsigned int`s to be a desirable `const` or `constexpr` (and usually also `static`).
|
|
|
|
Boost macros allow this to be done portably, see
|
|
[@http://www.boost.org/doc/libs/1_58_0/libs/config/doc/html/boost_config/boost_macro_reference.html BOOST_CONSTEXPR_OR_CONST or BOOST_STATIC_CONSTEXPR].
|
|
|
|
(See also
|
|
[@http://www.loria.fr/~zimmerma/mca/mca-cup-0.5.9.pdf Richard P. Brent and Paul Zimmerman, Modern Computer Arithmetic]
|
|
Equation 3.8 on page 116).
|
|
|
|
[max_digits10_1] [/ example for using max_digits10]
|
|
|
|
[h4 round_style]
|
|
|
|
The rounding style determines how the result of floating-point operations
|
|
is treated when the result cannot be [*exactly represented] in the significand.
|
|
Various rounding modes may be provided:
|
|
|
|
* round to nearest up or down (default for floating-point types).
|
|
* round up (toward positive infinity).
|
|
* round down (toward negative infinity).
|
|
* round toward zero (integer types).
|
|
* no rounding (if decimal radix).
|
|
* rounding mode is not determinable.
|
|
|
|
For integer types, `std::numeric_limits<T>::round_style` is always towards zero, so
|
|
|
|
std::numeric_limits<T>::round_style == std::round_to_zero;
|
|
|
|
A decimal type, `cpp_dec_float` rounds in no particular direction,
|
|
which is to say it doesn't round at all.
|
|
And since there are several guard digits,
|
|
it's not really the same as truncation (round toward zero) either.
|
|
|
|
For floating-point types, it is normal to round to nearest.
|
|
|
|
std::numeric_limits<T>::round_style == std::round_to_nearest;
|
|
|
|
See function `std::numeric_limits<T>::round_error` for the maximum error (in ULP)
|
|
that rounding can cause.
|
|
|
|
[h4 has_denorm_loss]
|
|
|
|
`true` if a loss of precision is detected as a
|
|
[@http://en.wikipedia.org/wiki/Denormalization denormalization] loss,
|
|
rather than an inexact result.
|
|
|
|
Always `false` for integer types.
|
|
|
|
`false` for all types which do not have `has_denorm` == `std::denorm_present`.
|
|
|
|
[h4 denorm_style]
|
|
|
|
[@http://en.wikipedia.org/wiki/Denormal_number Denormalized values] are
|
|
representations with a variable number of exponent bits that can permit
|
|
gradual underflow, so that, if type T is `double`.
|
|
|
|
std::numeric_limits<T>::denorm_min() < std::numeric_limits<T>::min()
|
|
|
|
A type may have any of the following `enum float_denorm_style` values:
|
|
|
|
* `std::denorm_absent`, if it does not allow denormalized values.
|
|
(Always used for all integer and exact types).
|
|
* `std::denorm_present`, if the floating-point type allows denormalized values.
|
|
*`std::denorm_indeterminate`, if indeterminate at compile time.
|
|
|
|
[h4 Tinyness before rounding]
|
|
|
|
`bool std::numeric_limits<T>::tinyness_before`
|
|
|
|
`true` if a type can determine that a value is too small
|
|
to be represent as a normalized value before rounding it.
|
|
|
|
Generally true for `is_iec559` floating-point built-in types,
|
|
but false for integer types.
|
|
|
|
Standard-compliant IEEE 754 floating-point implementations may detect the floating-point underflow at three predefined moments:
|
|
|
|
# After computation of a result with absolute value smaller than
|
|
`std::numeric_limits<T>::min()`,
|
|
such implementation detects ['tinyness before rounding] (e.g. UltraSparc).
|
|
|
|
# After rounding of the result to `std::numeric_limits<T>::digits` bits,
|
|
if the result is tiny, such implementation detects ['tinyness after rounding]
|
|
(e.g. SuperSparc).
|
|
|
|
# If the conversion of the rounded tiny result to subnormal form
|
|
resulted in the loss of precision, such implementation detects ['denorm loss].
|
|
|
|
[endsect] [/section:constants std::numeric_limits<> Constants]
|
|
|
|
[section:functions `std::numeric_limits<>` functions]
|
|
|
|
[h4:max_function `max` function]
|
|
|
|
Function `(std::numeric_limits<T>::max)()` returns the largest finite value
|
|
that can be represented by the type T. If there is no such value (and
|
|
`numeric_limits<T>::bounded` is `false`) then returns `T()`.
|
|
|
|
For built-in types there is usually a corresponding MACRO value TYPE_MAX,
|
|
where TYPE is CHAR, INT, FLOAT etc.
|
|
|
|
Other types, including those provided by a typedef,
|
|
for example `INT64_T_MAX` for `int64_t`, may provide a macro definition.
|
|
|
|
To cater for situations where no `numeric_limits` specialization is available
|
|
(for example because the precision of the type varies at runtime),
|
|
packaged versions of this (and other functions) are provided using
|
|
|
|
#include <boost/math/tools/precision.hpp>
|
|
|
|
T = boost::math::tools::max_value<T>();
|
|
|
|
Of course, these simply use `(std::numeric_limits<T>::max)()` if available,
|
|
but otherwise 'do something sensible'.
|
|
|
|
[h4 lowest function]
|
|
|
|
Since C++11: `std::numeric_limits<T>::lowest()` is
|
|
|
|
* For integral types, the same as function `min()`.
|
|
* For floating-point types, generally the negative of `max()`
|
|
(but implementation-dependent).
|
|
|
|
[digits10_5]
|
|
|
|
[h4:min_function `min` function]
|
|
|
|
Function `(std::numeric_limits<T>::min)()` returns the minimum finite value
|
|
that can be represented by the type T.
|
|
|
|
For built-in types, there is usually a corresponding MACRO value TYPE_MIN,
|
|
where TYPE is CHAR, INT, FLOAT etc.
|
|
|
|
Other types, including those provided by a `typedef`,
|
|
for example, `INT64_T_MIN` for `int64_t`, may provide a macro definition.
|
|
|
|
For floating-point types,
|
|
it is more fully defined as the ['minimum positive normalized value].
|
|
|
|
See `std::numeric_limits<T>::denorm_min()` for the smallest denormalized value, provided
|
|
|
|
std::numeric_limits<T>::has_denorm == std::denorm_present
|
|
|
|
To cater for situations where no `numeric_limits` specialization is available
|
|
(for example because the precision of the type varies at runtime),
|
|
packaged versions of this (and other functions) are provided using
|
|
|
|
#include <boost/math/tools/precision.hpp>
|
|
|
|
T = boost::math::tools::min_value<T>();
|
|
|
|
Of course, these simply use `std::numeric_limits<T>::min()` if available.
|
|
|
|
[h4 denorm_min function]
|
|
|
|
Function `std::numeric_limits<T>::denorm_min()`
|
|
returns the smallest
|
|
[@http://en.wikipedia.org/wiki/Denormal_number denormalized value],
|
|
provided
|
|
|
|
std::numeric_limits<T>::has_denorm == std::denorm_present
|
|
|
|
[denorm_min_1]
|
|
|
|
The exponent is effectively reduced from -308 to -324
|
|
(though it remains encoded as zero and leading zeros appear in the significand,
|
|
thereby losing precision until the significand reaches zero).
|
|
|
|
[h4 round_error]
|
|
|
|
Function `std::numeric_limits<T>::round_error()` returns the maximum error
|
|
(in units of [@http://en.wikipedia.org/wiki/Unit_in_the_last_place ULP])
|
|
that can be caused by any basic arithmetic operation.
|
|
|
|
round_style == std::round_indeterminate;
|
|
|
|
The rounding style is indeterminable at compile time.
|
|
|
|
For floating-point types, when rounding is to nearest,
|
|
only half a bit is lost by rounding, and `round_error == 0.5`.
|
|
In contrast when rounding is towards zero, or plus/minus infinity,
|
|
we can loose up to one bit from rounding, and `round_error == 1`.
|
|
|
|
For integer types, rounding always to zero, so at worst almost one bit can be rounded,
|
|
so `round_error == 1`.
|
|
|
|
`round_error()` can be used with `std::numeric_limits<T>::epsilon()` to estimate
|
|
the maximum potential error caused by rounding. For typical floating-point types,
|
|
`round_error() = 1/2`, so half epsilon is the maximum potential error.
|
|
|
|
[round_error_1]
|
|
|
|
There are, of course, many occasions when much bigger loss of precision occurs,
|
|
for example, caused by
|
|
[@http://en.wikipedia.org/wiki/Loss_of_significance Loss of significance or cancellation error]
|
|
or very many iterations.
|
|
|
|
[h4:epsilon epsilon]
|
|
|
|
Function `std::numeric_limits<T>::epsilon()` is meaningful only for non-integral types.
|
|
|
|
It returns the difference between `1.0` and the next value representable
|
|
by the floating-point type T.
|
|
So it is a one least-significant-bit change in this floating-point value.
|
|
|
|
For `double` (`float_64t`) it is `2.2204460492503131e-016`
|
|
showing all possibly significant 17 decimal digits.
|
|
|
|
[epsilon_1]
|
|
|
|
We can explicitly increment by one bit using the function `boost::math::float_next()`
|
|
and the result is the same as adding `epsilon`.
|
|
|
|
[epsilon_2]
|
|
|
|
Adding any smaller value, like half `epsilon`, will have no effect on this value.
|
|
|
|
[epsilon_3]
|
|
|
|
So this cancellation error leaves the values equal, despite adding half `epsilon`.
|
|
|
|
To achieve greater portability over platform and floating-point type,
|
|
Boost.Math and Boost.Multiprecision provide a package of functions that
|
|
'do something sensible' if the standard `numeric_limits` is not available.
|
|
To use these `#include <boost/math/tools/precision.hpp>`.
|
|
|
|
[epsilon_4]
|
|
|
|
[h5:FP_tolerance Tolerance for Floating-point Comparisons]
|
|
|
|
[@https://en.wikipedia.org/wiki/Machine_epsilon Machine epsilon [epsilon]]
|
|
is very useful to compute a tolerance when comparing floating-point values,
|
|
a much more difficult task than is commonly imagined.
|
|
|
|
The C++ standard specifies [@https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon `std::numeric_limits<>::epsilon()`]
|
|
and Boost.Multiprecision implements this (where possible) for its program-defined types analogous to the
|
|
__fundamental floating-point types like `double` `float`.
|
|
|
|
For more information than you probably want (but still need) see
|
|
[@http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html What Every Computer Scientist Should Know About Floating-Point Arithmetic]
|
|
|
|
The naive test comparing the absolute difference between two values and a tolerance
|
|
does not give useful results if the values are too large or too small.
|
|
|
|
So Boost.Test uses an algorithm first devised by Knuth
|
|
for reliably checking if floating-point values are close enough.
|
|
|
|
See Donald. E. Knuth. The art of computer programming (vol II).
|
|
Copyright 1998 Addison-Wesley Longman, Inc., 0-201-89684-2.
|
|
Addison-Wesley Professional; 3rd edition. (The relevant equations are in paragraph 4.2.2, Eq. 36 and 37.)
|
|
|
|
See [@https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/testing_tools/extended_comparison/floating_point/floating_points_comparison_theory.html Boost.Math floating_point comparison]
|
|
for more details.
|
|
|
|
See also:
|
|
|
|
[@http://adtmag.com/articles/2000/03/15/comparing-floats-how-to-determine-if-floating-quantities-are-close-enough-once-a-tolerance-has-been.aspx Alberto Squassia, Comparing floats]
|
|
|
|
[@http://adtmag.com/articles/2000/03/16/comparing-floats-how-to-determine-if-floating-quantities-are-close-enough-once-a-tolerance-has-been.aspx Alberto Squassia, Comparing floats code]
|
|
|
|
[@https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/testing_tools/extended_comparison/floating_point.html Boost.Test Floating-Point_Comparison]
|
|
|
|
[tolerance_1]
|
|
|
|
used thus:
|
|
|
|
cd ./test
|
|
BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
|
|
|
|
(There is also a version BOOST_CHECK_CLOSE using tolerance as a [*percentage] rather than a fraction;
|
|
usually the fraction version is simpler to use).
|
|
|
|
[tolerance_2]
|
|
|
|
[h4:infinity Infinity - positive and negative]
|
|
|
|
For floating-point types only, for which
|
|
`std::numeric_limits<T>::has_infinity == true`,
|
|
function `std::numeric_limits<T>::infinity()`
|
|
provides an implementation-defined representation for [infin].
|
|
|
|
The 'representation' is a particular bit pattern reserved for infinity.
|
|
For IEEE754 system (for which `std::numeric_limits<T>::is_iec559 == true`)
|
|
[@http://en.wikipedia.org/wiki/IEEE_754-1985#Positive_and_negative_infinity positive and negative infinity]
|
|
are assigned bit patterns for all defined floating-point types.
|
|
|
|
Confusingly, the string resulting from outputting this representation, is also
|
|
implementation-defined. And the string that can be input to generate the representation is also implementation-defined.
|
|
|
|
For example, the output is `1.#INF` on Microsoft systems, but `inf` on most *nix platforms.
|
|
|
|
This implementation-defined-ness has hampered use of infinity (and NaNs)
|
|
but Boost.Math and Boost.Multiprecision work hard to provide a sensible representation
|
|
for [*all] floating-point types, not just the built-in types,
|
|
which with the use of suitable facets to define the input and output strings, makes it possible
|
|
to use these useful features portably and including Boost.Serialization.
|
|
|
|
[h4 Not-A-Number NaN]
|
|
|
|
[h5 Quiet_NaN]
|
|
|
|
For floating-point types only, for which
|
|
`std::numeric_limits<T>::has_quiet_NaN == true`,
|
|
function `std::numeric_limits<T>::quiet_NaN()`
|
|
provides an implementation-defined representation for NaN.
|
|
|
|
[@http://en.wikipedia.org/wiki/NaN NaNs] are values to indicate that the
|
|
result of an assignment or computation is meaningless.
|
|
A typical example is `0/0` but there are many others.
|
|
|
|
NaNs may also be used, to represent missing values: for example,
|
|
these could, by convention, be ignored in calculations of statistics like means.
|
|
|
|
Many of the problems with a representation for
|
|
[@http://en.wikipedia.org/wiki/NaN Not-A-Number] has hampered portable use,
|
|
similar to those with infinity.
|
|
|
|
[nan_1]
|
|
|
|
But using Boost.Math and suitable facets can permit portable use
|
|
of both NaNs and positive and negative infinity.
|
|
|
|
[facet_1]
|
|
|
|
[h5 Signaling NaN]
|
|
|
|
For floating-point types only, for which
|
|
`std::numeric_limits<T>::has_signaling_NaN == true`,
|
|
function `std::numeric_limits<T>::signaling_NaN()`
|
|
provides an implementation-defined representation for NaN that causes a hardware trap.
|
|
It should be noted however, that at least one implementation of this function causes a hardware
|
|
trap to be triggered simply by calling `std::numeric_limits<T>::signaling_NaN()`, and not only
|
|
by using the value returned.
|
|
|
|
[endsect] [/section:functions std::numeric_limits<> functions]
|
|
|
|
[/ Tables of values for numeric_limits for various built-in and cpp_bin_float types]
|
|
[include numeric_limits_32_tables.qbk]
|
|
[/include numeric_limits_64_tables.qbk]
|
|
|
|
[section:how_to_tell How to Determine the Kind of a Number From `std::numeric_limits`]
|
|
|
|
Based on the information above, one can see that different kinds of numbers can be
|
|
differentiated based on the information stored in `std::numeric_limits`. This is
|
|
in addition to the traits class [link boost_multiprecision.ref.number.traits_class_support
|
|
number_category] provided by this library.
|
|
|
|
[h4 Integer Types]
|
|
|
|
For an integer type T, all of the following conditions hold:
|
|
|
|
std::numeric_limits<T>::is_specialized == true
|
|
std::numeric_limits<T>::is_integer == true
|
|
std::numeric_limits<T>::is_exact == true
|
|
std::numeric_limits<T>::min_exponent == 0
|
|
std::numeric_limits<T>::max_exponent == 0
|
|
std::numeric_limits<T>::min_exponent10 == 0
|
|
std::numeric_limits<T>::max_exponent10 == 0
|
|
|
|
In addition the type is /signed/ if:
|
|
|
|
std::numeric_limits<T>::is_signed == true
|
|
|
|
If the type is arbitrary precision then:
|
|
|
|
std::numeric_limits<T>::is_bounded == false
|
|
|
|
Otherwise the type is bounded, and returns a non zero value
|
|
from:
|
|
|
|
std::numeric_limits<T>::max()
|
|
|
|
and has:
|
|
|
|
std::numeric_limits<T>::is_modulo == true
|
|
|
|
if the type implements modulo arithmetic on overflow.
|
|
|
|
[h4 Rational Types]
|
|
|
|
Rational types are just like integers except that:
|
|
|
|
std::numeric_limits<T>::is_integer == false
|
|
|
|
[h4 Fixed Precision Types]
|
|
|
|
There appears to be no way to tell these apart from rational types, unless they set:
|
|
|
|
std::numeric_limits<T>::is_exact == false
|
|
|
|
This is because these types are in essence a rational type with a fixed denominator.
|
|
|
|
[h4 floating-point Types]
|
|
|
|
For a floating-point type T, all of the following conditions hold:
|
|
|
|
std::numeric_limits<T>::is_specialized == true
|
|
std::numeric_limits<T>::is_integer == false
|
|
std::numeric_limits<T>::is_exact == false
|
|
std::numeric_limits<T>::min_exponent != 0
|
|
std::numeric_limits<T>::max_exponent != 0
|
|
std::numeric_limits<T>::min_exponent10 != 0
|
|
std::numeric_limits<T>::max_exponent10 != 0
|
|
|
|
In addition the type is /signed/ if:
|
|
|
|
std::numeric_limits<T>::is_signed == true
|
|
|
|
And the type may be decimal or binary depending on the value of:
|
|
|
|
std::numeric_limits<T>::radix
|
|
|
|
In general, there are no arbitrary precision floating-point types, and so:
|
|
|
|
std::numeric_limits<T>::is_bounded == false
|
|
|
|
[h4 Exact floating-point Types]
|
|
|
|
Exact floating-point types are a [@http://en.wikipedia.org/wiki/Field_%28mathematics%29 field]
|
|
composed of an arbitrary precision integer scaled by an exponent. Such types
|
|
have no division operator and are the same as floating-point types except:
|
|
|
|
std::numeric_limits<T>::is_exact == true
|
|
|
|
[h4 Complex Numbers]
|
|
|
|
For historical reasons, complex numbers do not specialize `std::numeric_limits`, instead you must
|
|
inspect `std::numeric_limits<typename T::value_type>`.
|
|
|
|
[endsect] [/section:how_to_tell How to Determine the Kind of a Number From `std::numeric_limits`]
|
|
|
|
[endsect] [/section:limits Numeric Limits]
|
|
|
|
|
|
[section:input_output Input Output]
|
|
|
|
[h4 Loopback testing]
|
|
|
|
['Loopback] or ['round-tripping] refers to writing out a value as a decimal digit string using `std::iostream`,
|
|
usually to a `std::stringstream`, and then reading the string back in to another value,
|
|
and confirming that the two values are identical. A trivial example using `float` is:
|
|
|
|
float write; // Value to round-trip.
|
|
std::stringstream ss; // Read and write std::stringstream.
|
|
ss.precision(std::numeric_limits<T>::max_digits10); // Ensure all potentially significant bits are output.
|
|
ss.flags(std::ios_base::fmtflags(std::ios_base::scientific)); // Use scientific format.
|
|
ss << write; // Output to string.
|
|
float read; // Expected.
|
|
ss >> read; // Read decimal digits string from stringstream.
|
|
BOOST_CHECK_EQUAL(write, read); // Should be the same.
|
|
|
|
and this can be run in a loop for all possible values of a 32-bit float.
|
|
For other floating-point types `T`, including built-in `double`,
|
|
it takes far too long to test all values,
|
|
so a reasonable test strategy is to use a large number of random values.
|
|
|
|
T write;
|
|
std::stringstream ss;
|
|
ss.precision(std::numeric_limits<T>::max_digits10); // Ensure all potentially significant bits are output.
|
|
ss.flags(f); // Changed from default iostream format flags if desired.
|
|
ss << write; // Output to stringstream.
|
|
|
|
T read;
|
|
ss >> read; // Get read using operator>> from stringstream.
|
|
BOOST_CHECK_EQUAL(read, write);
|
|
|
|
read = static_cast<T>(ss.str()); // Get read by converting from decimal digits string representation of write.
|
|
BOOST_CHECK_EQUAL(read, write);
|
|
|
|
read = static_cast<T>(write.str(0, f)); // Get read using format specified when written.
|
|
BOOST_CHECK_EQUAL(read, write);
|
|
|
|
|
|
The test at
|
|
[@../../test/test_cpp_bin_float_io.cpp test_cpp_bin_float_io.cpp]
|
|
allows any floating-point type to be ['round_tripped] using a wide range of fairly random values.
|
|
It also includes tests compared a collection of
|
|
[@../../test/string_data.ipp stringdata] test cases in a file.
|
|
|
|
[h4 Comparing with output using Built-in types]
|
|
|
|
One can make some comparisons with the output of
|
|
|
|
<number<cpp_bin_float<53, digit_count_2> >
|
|
|
|
which has the same number of significant bits (53) as 64-bit double precision floating-point.
|
|
|
|
However, although most outputs are identical, there are differences on some platforms
|
|
caused by the implementation-dependent behaviours allowed by the C99 specification
|
|
[@http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf C99 ISO/IEC 9899:TC2],
|
|
incorporated by C++.
|
|
|
|
[:['"For e, E, f, F, g, and G conversions, if the number of significant decimal digits
|
|
is at most DECIMAL_DIG, then the result should be correctly rounded.
|
|
If the number of significant decimal digits is more than DECIMAL_DIG
|
|
but the source value is exactly representable with DECIMAL_DIG digits,
|
|
then the result should be an exact representation with trailing zeros.
|
|
Otherwise, the source value is bounded by two adjacent decimal strings L < U,
|
|
both having DECIMAL_DIG significant digits;
|
|
the value of the resultant decimal string D should satisfy L<= D <= U,
|
|
with the extra stipulation that the error should have a correct sign
|
|
for the current rounding direction."]]
|
|
|
|
So not only is correct rounding for the full number of digits not required,
|
|
but even if the *optional* recommended practice is followed,
|
|
then the value of these last few digits is unspecified
|
|
as long as the value is within certain bounds.
|
|
|
|
[note Do not expect the output from different platforms
|
|
to be [*identical], but `cpp_dec_float`, `cpp_bin_float` (and other backends) outputs should be
|
|
correctly rounded to the number of digits requested by the set precision and format.]
|
|
|
|
|
|
[h4 Macro BOOST_MP_MIN_EXPONENT_DIGITS]
|
|
|
|
[@http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf C99 Standard]
|
|
for [/e and E] format specifiers, 7.19.6 Formatted input/output functions requires:
|
|
|
|
\"The exponent always contains at least two digits,
|
|
and only as many more digits as necessary to represent the exponent.\"
|
|
|
|
So to conform to the C99 standard (incorporated by C++)
|
|
|
|
#define BOOST_MP_MIN_EXPONENT_DIGITS 2
|
|
|
|
Confusingly, Microsoft (and MinGW) do not conform to this standard and provide
|
|
[*at least three digits], for example `1e+001`.
|
|
So if you want the output to match that from
|
|
built-in floating-point types on compilers that use Microsofts runtime then use:
|
|
|
|
#define BOOST_MP_MIN_EXPONENT_DIGITS 3
|
|
|
|
Also useful to get the minimum exponent field width is
|
|
|
|
#define BOOST_MP_MIN_EXPONENT_DIGITS 1
|
|
|
|
producing a compact output like `2e+4`,
|
|
useful when conserving space is important.
|
|
|
|
Larger values are also supported, for example, value 4 for `2e+0004`
|
|
which may be useful to ensure that columns line up.
|
|
|
|
[endsect] [/section:input_output Input Output]
|
|
|
|
[section:hash Hash Function Support]
|
|
|
|
[hash1]
|
|
|
|
[hash2]
|
|
|
|
[hash3]
|
|
|
|
[hash4]
|
|
|
|
[endsect][/hash]
|
|
|
|
[section:eigen Eigen Interoperability]
|
|
|
|
This library provides the header:
|
|
|
|
#include <boost/multiprecision/eigen.hpp>
|
|
|
|
which defines the traits classes and functions that the Eigen library needs all user-defined number types to provide.
|
|
|
|
For example the following code performs quad-precision matrix solving on complex numbers:
|
|
|
|
[eigen_eg]
|
|
|
|
Which produces the following output:
|
|
|
|
[eigen_out]
|
|
|
|
[endsect]
|
|
[endsect]
|
|
|
|
[section:ref Reference]
|
|
|
|
[section:number number]
|
|
|
|
[h4 Synopsis]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
enum expression_template_option { et_on = 1, et_off = 0 };
|
|
|
|
template <class Backend> struct expression_template_default
|
|
{ static const expression_template_option value = et_on; };
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
|
|
class number
|
|
{
|
|
public:
|
|
typedef Backend backend_type;
|
|
typedef typename component_type<self_type>::type value_type;
|
|
|
|
number();
|
|
number(see-below);
|
|
number& operator=(see-below);
|
|
number& assign(see-below);
|
|
|
|
// Member operators
|
|
number& operator+=(const ``['see-below]``&);
|
|
number& operator-=(const ``['see-below]``&);
|
|
number& operator*=(const ``['see-below]``&);
|
|
number& operator/=(const ``['see-below]``&);
|
|
number& operator++();
|
|
number& operator--();
|
|
number operator++(int);
|
|
number operator--(int);
|
|
|
|
number& operator%=(const ``['see-below]``&);
|
|
number& operator&=(const ``['see-below]``&);
|
|
number& operator|=(const ``['see-below]``&);
|
|
number& operator^=(const ``['see-below]``&);
|
|
number& operator<<=(const ``['integer-type]``&);
|
|
number& operator>>=(const ``['integer-type]``&);
|
|
|
|
// Use in Boolean context:
|
|
operator ``['convertible-to-bool-type]``()const;
|
|
// swap:
|
|
void swap(number& other);
|
|
// Sign:
|
|
bool is_zero()const;
|
|
int sign()const;
|
|
// string conversion:
|
|
std::string str()const;
|
|
// Generic conversion mechanism
|
|
template <class T>
|
|
T convert_to()const;
|
|
template <class T>
|
|
explicit operator T ()const;
|
|
// precision control:
|
|
static unsigned default_precision();
|
|
static void default_precision(unsigned digits10);
|
|
unsigned precision()const;
|
|
void precision(unsigned digits10);
|
|
// Comparison:
|
|
int compare(const number<Backend>& o)const;
|
|
template <class V>
|
|
typename enable_if<is_convertible<V, number<Backend, ExpressionTemplates> >, int>::type
|
|
compare(const V& o)const;
|
|
// real and imaginary parts:
|
|
value_type real()const;
|
|
value_type imag()const;
|
|
template <class T>
|
|
void real(const T& val);
|
|
template <class T>
|
|
void imag(const T& val);
|
|
// Access to the underlying implementation:
|
|
Backend& backend();
|
|
const Backend& backend()const;
|
|
};
|
|
|
|
// Non member operators:
|
|
``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator*(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator/(const ``['see-below]``&, const ``['see-below]``&);
|
|
// Integer only operations:
|
|
``['unmentionable-expression-template-type]`` operator%(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator&(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator|(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator^(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator<<(const ``['see-below]``&, const ``['integer-type]``&);
|
|
``['unmentionable-expression-template-type]`` operator>>(const ``['see-below]``&, const ``['integer-type]``&);
|
|
// Comparison operators:
|
|
bool operator==(const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator!=(const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator< (const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator> (const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator<=(const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator>=(const ``['see-below]``&, const ``['see-below]``&);
|
|
|
|
// Swap:
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b);
|
|
|
|
// iostream support:
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
std::ostream& operator << (std::ostream& os, const number<Backend, ExpressionTemplates>& r);
|
|
std::ostream& operator << (std::ostream& os, const ``['unmentionable-expression-template-type]``& r);
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
std::istream& operator >> (std::istream& is, number<Backend, ExpressionTemplates>& r);
|
|
|
|
// Arithmetic with a higher precision result:
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& add(ResultType& result, const Source1& a, const Source2& b);
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& subtract(ResultType& result, const Source1& a, const Source2& b);
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& multiply(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
// min and max overloads:
|
|
``['number]`` min (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` max (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
|
|
// C99 Non-member function standard library support:
|
|
``['unmentionable-expression-template-type]`` abs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` acos (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` acosh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` asin (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` asinh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` atan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` atan2 (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` atanh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` cbrt (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ceil (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` copysign (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cos (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cosh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` erf (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` erfc (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` exp (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` exp2 (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` expm1 (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fabs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fdim (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` floor (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fma (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fmin (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fmax (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fmod (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` frexp (const ``['number-or-expression-template-type]``&, ``['integer-type]``*);
|
|
``['unmentionable-expression-template-type]`` hypot (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['integer-type]`` ilogb (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ldexp (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
|
|
``['number]`` lgamma (const ``['number-or-expression-template-type]``&);
|
|
long long llrint (const ``['number-or-expression-template-type]``&);
|
|
long long llround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log2 (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log10 (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` log1p (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` logb (const ``['number-or-expression-template-type]``&);
|
|
long lrint (const ``['number-or-expression-template-type]``&);
|
|
long lround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` modf (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` nearbyint (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` nextafter (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` nexttoward (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` pow (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` remainder (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` remquo (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, int*);
|
|
``['unmentionable-expression-template-type]`` rint (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` round (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` scalbn (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
|
|
``['unmentionable-expression-template-type]`` scalbln (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
|
|
``['unmentionable-expression-template-type]`` sin (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sinh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sqrt (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tanh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` tgamma (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` trunc (const ``['number-or-expression-template-type]``&);
|
|
|
|
int fpclassify (const ``['number-or-expression-template-type]``&);
|
|
bool isfinite (const ``['number-or-expression-template-type]``&);
|
|
bool isinf (const ``['number-or-expression-template-type]``&);
|
|
bool isnan (const ``['number-or-expression-template-type]``&);
|
|
bool isnormal (const ``['number-or-expression-template-type]``&);
|
|
int signbit (const ``['number-or-expression-template-type]``&);
|
|
|
|
bool isgreater (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool isgreaterequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool isless (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool islessequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool islessgreater(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool isunordered(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
// Complex number functions:
|
|
``['number<...>::value_type]`` real (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` imag (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` abs (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` arg (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` norm (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` conj (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` proj (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` polar (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
// Misc other common C library functions:
|
|
``['unmentionable-expression-template-type]`` itrunc (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ltrunc (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` lltrunc(const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` iround (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` changesign(const ``['number-or-expression-template-type]``&);
|
|
``['number]`` copysign(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
|
|
// Traits support:
|
|
template <class T>
|
|
struct component_type;
|
|
template <class T>
|
|
struct number_category;
|
|
template <class T>
|
|
struct is_number;
|
|
template <class T>
|
|
struct is_number_expression;
|
|
|
|
// Integer specific functions:
|
|
``['unmentionable-expression-template-type]`` gcd(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` lcm(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` pow(const ``['number-or-expression-template-type]``&, unsigned);
|
|
``['unmentionable-expression-template-type]`` powm(const ``['number-or-expression-template-type]``& b, const ``['number-or-expression-template-type]``& p, const ``['number-or-expression-template-type]``& m);
|
|
``['unmentionable-expression-template-type]`` sqrt(const ``['number-or-expression-template-type]``&);
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
number<Backend, EXpressionTemplates> sqrt(const ``['number-or-expression-template-type]``&, number<Backend, EXpressionTemplates>&);
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
void divide_qr(const ``['number-or-expression-template-type]``& x, const ``['number-or-expression-template-type]``& y,
|
|
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r);
|
|
template <class Integer>
|
|
Integer integer_modulus(const ``['number-or-expression-template-type]``& x, Integer val);
|
|
unsigned lsb(const ``['number-or-expression-template-type]``& x);
|
|
unsigned msb(const ``['number-or-expression-template-type]``& x);
|
|
template <class Backend, class ExpressionTemplates>
|
|
bool bit_test(const number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
template <class Backend, class ExpressionTemplates>
|
|
number<Backend, ExpressionTemplates>& bit_set(number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
template <class Backend, class ExpressionTemplates>
|
|
number<Backend, ExpressionTemplates>& bit_unset(number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
template <class Backend, class ExpressionTemplates>
|
|
number<Backend, ExpressionTemplates>& bit_flip(number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
template <class Engine>
|
|
bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials, Engine& gen);
|
|
bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials);
|
|
|
|
// Rational number support:
|
|
typename component_type<``['number-or-expression-template-type]``>::type numerator (const ``['number-or-expression-template-type]``&);
|
|
typename component_type<``['number-or-expression-template-type]``>::type denominator(const ``['number-or-expression-template-type]``&);
|
|
|
|
}} // namespaces
|
|
|
|
namespace boost{ namespace math{
|
|
|
|
// Boost.Math interoperability functions:
|
|
int fpclassify (const ``['number-or-expression-template-type]``&, int);
|
|
bool isfinite (const ``['number-or-expression-template-type]``&, int);
|
|
bool isnan (const ``['number-or-expression-template-type]``&, int);
|
|
bool isinf (const ``['number-or-expression-template-type]``&, int);
|
|
bool isnormal (const ``['number-or-expression-template-type]``&, int);
|
|
|
|
}} // namespaces
|
|
|
|
// numeric_limits support:
|
|
namespace std{
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
struct numeric_limits<boost::multiprecision<Backend, ExpressionTemplates> >
|
|
{
|
|
/* Usual members here */
|
|
};
|
|
|
|
}
|
|
|
|
[h4 Description]
|
|
|
|
enum expression_template_option { et_on = 1, et_off = 0 };
|
|
|
|
This enumerated type is used to specify whether expression templates are turned on (et_on) or turned off (et_off).
|
|
|
|
template <class Backend> struct expression_template_default
|
|
{ static const expression_template_option value = et_on; };
|
|
|
|
This traits class specifies the default expression template option to be used with a particular Backend type.
|
|
It defaults to `et_on`.
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
|
|
class number;
|
|
|
|
Class `number` has two template arguments:
|
|
|
|
[variablelist
|
|
[[Backend][The actual arithmetic back-end that does all the work.]]
|
|
[[ExpressionTemplates][A Boolean value: when `et_on`, then expression templates are enabled, otherwise when set to `et_off` they are disabled.
|
|
The default for this parameter is computed via the traits class `expression_template_default` whose member `value` defaults to `et_on` unless
|
|
the traits class is specialized for a particular backend.]]
|
|
]
|
|
|
|
number();
|
|
number(see-below);
|
|
number& operator=(see-below);
|
|
number& assign(see-below);
|
|
|
|
Type `number` is default constructible, and both copy constructible and assignable from:
|
|
|
|
* Itself.
|
|
* An expression template which is the result of one of the arithmetic operators.
|
|
* Any builtin arithmetic type, as long as the result would not be lossy (for example float to integer conversion).
|
|
* Any type that the Backend is implicitly constructible or assignable from.
|
|
* An rvalue reference to another `number`. Move-semantics are used for construction if the backend also
|
|
supports rvalue reference construction. In the case of assignment, move semantics are always supported
|
|
when the argument is an rvalue reference irrespective of the backend.
|
|
* Any type in the same family, as long as no loss of precision is involved. For example from `int128_t` to `int256_t`,
|
|
or `cpp_dec_float_50` to `cpp_dec_float_100`.
|
|
|
|
Type `number` is explicitly constructible from:
|
|
|
|
* Any type mentioned above.
|
|
* A `std::string` or any type which is convertible to `const char*`.
|
|
* Any arithmetic type (including those that would result in lossy conversions).
|
|
* Any type in the same family, including those that result in loss of precision.
|
|
* Any type that the Backend is explicitly constructible from.
|
|
* Any pair of types for which a generic interconversion exists: that is from integer to integer, integer
|
|
to rational, integer to float, rational to rational, rational to float, or float to float.
|
|
|
|
The assign member function is available for any type for which an explicit converting constructor exists.
|
|
It is intended to be used where a temporary generated from an explicit assignment would be expensive, for example:
|
|
|
|
mpfr_float_50 f50;
|
|
mpfr_float_100 f100;
|
|
|
|
f50 = static_cast<mpfr_float_50>(f100); // explicit cast create a temporary
|
|
f50.assign(f100); // explicit call to assign create no temporary
|
|
|
|
In addition, if the type has multiple components (for example rational or complex number types), then there is a
|
|
two argument constructor:
|
|
|
|
number(arg1, arg2);
|
|
|
|
Where the two args must either be arithmetic types, or types that are convertible to the two components of `this`.
|
|
|
|
Finally, when the type has a variable precision, then there are constructors:
|
|
|
|
number(arg1, precision);
|
|
number(arg1, arg2, precision);
|
|
|
|
Where `precision` is an unsigned value, the 2 arg version is active for scalar types and/or copy-construction with specific precision, and the 3-arg version for complex types.
|
|
|
|
Likewise `assign` has a 2-arg overloaded, with the second argument being the precision.
|
|
|
|
number& operator+=(const ``['see-below]``&);
|
|
number& operator-=(const ``['see-below]``&);
|
|
number& operator*=(const ``['see-below]``&);
|
|
number& operator/=(const ``['see-below]``&);
|
|
number& operator++();
|
|
number& operator--();
|
|
number operator++(int);
|
|
number operator--(int);
|
|
// Integer only operations:
|
|
number& operator%=(const ``['see-below]``&);
|
|
number& operator&=(const ``['see-below]``&);
|
|
number& operator|=(const ``['see-below]``&);
|
|
number& operator^=(const ``['see-below]``&);
|
|
number& operator<<=(const ``['integer-type]``&);
|
|
number& operator>>=(const ``['integer-type]``&);
|
|
|
|
These operators all take their usual arithmetic meanings.
|
|
|
|
The arguments to these operators is either:
|
|
|
|
* Another `number<Backend, ExpressionTemplates>`.
|
|
* An expression template derived from `number<Backend>`.
|
|
* Any type implicitly convertible to `number<Backend, ExpressionTemplates>`, including some other instance of class `number`.
|
|
|
|
For the left and right shift operations, the argument must be a builtin
|
|
integer type with a positive value (negative values result in a `std::runtime_error` being thrown).
|
|
|
|
operator ``['convertible-to-bool-type]``()const;
|
|
|
|
Returns an ['unmentionable-type] that is usable in Boolean contexts (this allows `number` to be used in any
|
|
Boolean context - if statements, conditional statements, or as an argument to a logical operator - without
|
|
type `number` being convertible to type `bool`.
|
|
|
|
This operator also enables the use of `number` with any of the following operators:
|
|
`!`, `||`, `&&` and `?:`.
|
|
|
|
void swap(number& other);
|
|
|
|
Swaps `*this` with `other`.
|
|
|
|
bool is_zero()const;
|
|
|
|
Returns `true` is `*this` is zero, otherwise `false`.
|
|
|
|
int sign()const;
|
|
|
|
Returns a value less than zero if `*this` is negative, a value greater than zero if `*this` is positive, and zero
|
|
if `*this` is zero.
|
|
|
|
std::string str(unsigned precision, bool scientific = true)const;
|
|
|
|
Returns the number formatted as a string, with at least /precision/ digits, and in scientific format
|
|
if /scientific/ is true.
|
|
|
|
template <class T>
|
|
T convert_to()const;
|
|
|
|
template <class T>
|
|
explicit operator T ()const;
|
|
|
|
Provides a generic conversion mechanism to convert `*this` to type `T`. Type `T` may be any arithmetic type.
|
|
Optionally other types may also be supported by specific `Backend` types.
|
|
|
|
|
|
static unsigned default_precision();
|
|
static void default_precision(unsigned digits10);
|
|
unsigned precision()const;
|
|
void precision(unsigned digits10);
|
|
|
|
These functions are only available if the Backend template parameter supports runtime changes to precision. They get and set
|
|
the default precision and the precision of `*this` respectively.
|
|
|
|
int compare(const number<Backend, ExpressionTemplates>& o)const;
|
|
template <class V>
|
|
typename enable_if<is_convertible<V, number<Backend, ExpressionTemplates> >, int>::type
|
|
compare(const V& other)const;
|
|
|
|
Returns:
|
|
|
|
* A value less that 0 for `*this < other`
|
|
* A value greater that 0 for `*this > other`
|
|
* Zero for `*this == other`
|
|
|
|
value_type real()const;
|
|
value_type imag()const;
|
|
|
|
These return the real and imaginary parts respectively. If the number is not a complex type, then the imaginary part is always zero.
|
|
|
|
template <class T>
|
|
void real(const T& val);
|
|
template <class T>
|
|
void imag(const T& val);
|
|
|
|
These set the real and imaginary parts respectively of the number. If the number is not a complex type, then setting the real part
|
|
is equivalent to assignment, and attempting to set the imaginary part will result in a compile time error.
|
|
|
|
Backend& backend();
|
|
const Backend& backend()const;
|
|
|
|
Returns the underlying back-end instance used by `*this`.
|
|
|
|
[h4 Non-member operators]
|
|
|
|
// Non member operators:
|
|
``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator+(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator-(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator*(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator/(const ``['see-below]``&, const ``['see-below]``&);
|
|
// Integer only operations:
|
|
``['unmentionable-expression-template-type]`` operator%(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator&(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator|(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator^(const ``['see-below]``&, const ``['see-below]``&);
|
|
``['unmentionable-expression-template-type]`` operator<<(const ``['see-below]``&, const ``['integer-type]``&);
|
|
``['unmentionable-expression-template-type]`` operator>>(const ``['see-below]``&, const ``['integer-type]``&);
|
|
// Comparison operators:
|
|
bool operator==(const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator!=(const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator< (const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator> (const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator<=(const ``['see-below]``&, const ``['see-below]``&);
|
|
bool operator>=(const ``['see-below]``&, const ``['see-below]``&);
|
|
|
|
These operators all take their usual arithmetic meanings.
|
|
|
|
The arguments to these functions must contain at least one of the following:
|
|
|
|
* A `number`.
|
|
* An expression template type derived from `number`.
|
|
* Any type for which `number` has an implicit constructor - for example a builtin arithmetic type.
|
|
|
|
The return type of these operators is either:
|
|
|
|
* An ['unmentionable-type] expression template type when `ExpressionTemplates` is `true`.
|
|
* Type `number<Backend, et_off>` when `ExpressionTemplates` is `false`.
|
|
* Type `bool` if the operator is a comparison operator.
|
|
|
|
Finally note that the second argument to the left and right shift operations must be a builtin integer type,
|
|
and that the argument must be positive (negative arguments result in a `std::runtime_error` being thrown).
|
|
|
|
[h4 swap]
|
|
|
|
template <class Backend, ExpressionTemplates>
|
|
void swap(number<Backend, ExpressionTemplates>& a, number<Backend, ExpressionTemplates>& b);
|
|
|
|
Swaps `a` and `b`.
|
|
|
|
[h4 Iostream Support]
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
std::ostream& operator << (std::ostream& os, const number<Backend, ExpressionTemplates>& r);
|
|
template <class Unspecified...>
|
|
std::ostream& operator << (std::ostream& os, const unmentionable-expression-template& r);
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
inline std::istream& operator >> (std::istream& is, number<Backend, ExpressionTemplates>& r)
|
|
|
|
These operators provided formatted input-output operations on `number` types, and expression templates derived from them.
|
|
|
|
It's down to the back-end type to actually implement string conversion. However, the back-ends provided with
|
|
this library support all of the iostream formatting flags, field width and precision settings.
|
|
|
|
[h4 Arithmetic with a higher precision result]
|
|
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& add(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& subtract(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
template <class ResultType, class Source1 class Source2>
|
|
ResultType& multiply(ResultType& result, const Source1& a, const Source2& b);
|
|
|
|
These functions apply the named operator to the arguments ['a] and ['b] and store the
|
|
result in ['result], returning ['result]. In all cases they behave "as if"
|
|
arguments ['a] and ['b] were first promoted to type `ResultType` before applying the
|
|
operator, though particular backends may well avoid that step by way of an optimization.
|
|
|
|
The type `ResultType` must be an instance of class `number`, and the types `Source1` and `Source2`
|
|
may be either instances of class `number` or native integer types. The latter is an optimization
|
|
that allows arithmetic to be performed on native integer types producing an extended precision result.
|
|
|
|
[h4 Non-member standard library function support]
|
|
|
|
``['unmentionable-expression-template-type]`` abs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` acos (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` acosh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` asin (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` asinh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` atan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` atan2 (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` atanh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` cbrt (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ceil (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` copysign (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cos (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cosh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` erf (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` erfc (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` exp (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` exp2 (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` expm1 (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fabs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fdim (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` floor (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fma (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fmin (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fmax (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fmod (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` frexp (const ``['number-or-expression-template-type]``&, ``['integer-type]``*);
|
|
``['unmentionable-expression-template-type]`` hypot (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['integer-type]`` ilogb (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ldexp (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
|
|
``['number]`` lgamma (const ``['number-or-expression-template-type]``&);
|
|
long long llrint (const ``['number-or-expression-template-type]``&);
|
|
long long llround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log2 (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log10 (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` log1p (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` logb (const ``['number-or-expression-template-type]``&);
|
|
long lrint (const ``['number-or-expression-template-type]``&);
|
|
long lround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` modf (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` nearbyint (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` nextafter (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` nexttoward (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` pow (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` remainder (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` remquo (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&, int*);
|
|
``['unmentionable-expression-template-type]`` rint (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` round (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` scalbn (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
|
|
``['unmentionable-expression-template-type]`` scalbln (const ``['number-or-expression-template-type]``&, ``['integer-type]``);
|
|
``['unmentionable-expression-template-type]`` sin (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sinh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sqrt (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tanh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` tgamma (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` trunc (const ``['number-or-expression-template-type]``&);
|
|
|
|
int fpclassify (const ``['number-or-expression-template-type]``&);
|
|
bool isfinite (const ``['number-or-expression-template-type]``&);
|
|
bool isinf (const ``['number-or-expression-template-type]``&);
|
|
bool isnan (const ``['number-or-expression-template-type]``&);
|
|
bool isnormal (const ``['number-or-expression-template-type]``&);
|
|
int signbit (const ``['number-or-expression-template-type]``&);
|
|
|
|
bool isgreater (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool isgreaterequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool isless (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool islessequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool islessgreater(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
bool isunordered(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
|
|
These functions all behave exactly as their standard library C++11 counterparts do: their argument is either an instance of `number` or
|
|
an expression template derived from it; If the argument is of type `number<Backend, et_off>` then that is also the return type,
|
|
otherwise the return type is an expression template unless otherwise stated.
|
|
|
|
The integer type arguments to `ldexp`, `frexp`, `scalbn` and `ilogb` may be either type `int`, or the actual
|
|
type of the exponent of the number type.
|
|
|
|
Complex number types support the following functions:
|
|
|
|
// Complex number functions:
|
|
``['number<...>::value_type]`` real (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` imag (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` abs (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` arg (const ``['number-or-expression-template-type]``&);
|
|
``['number<...>::value_type]`` norm (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` conj (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` proj (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` polar (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
|
|
In addition the functions `real`, `imag`, `arg`, `norm`, `conj` and `proj` are overloaded for scalar (ie non-complex) types in the same
|
|
manner as `<complex>` and treat the argument as a value whose imaginary part is zero.
|
|
|
|
There are also some functions implemented for compatibility with the Boost.Math functions of the same name:
|
|
|
|
``['unmentionable-expression-template-type]`` itrunc (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ltrunc (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` lltrunc(const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` iround (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` changesign(const ``['number-or-expression-template-type]``&);
|
|
``['number]`` copysign(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
|
|
All these functions are normally implemented by the Backend type. However, default versions are provided for Backend types that
|
|
don't have native support for these functions. Please note however, that this default support requires the precision of the type
|
|
to be a compile time constant - this means for example that the [gmp] MPF Backend will not work with these functions when that type is
|
|
used at variable precision.
|
|
|
|
Also note that with the exception of `abs` that these functions can only be used with floating-point Backend types (if any other types
|
|
such as fixed precision or complex types are added to the library later, then these functions may be extended to support those number types).
|
|
|
|
The precision of these functions is generally determined by the backend implementation. For example the precision
|
|
of these functions when used with __mpfr_float_backend is determined entirely by [mpfr]. When these functions use our own
|
|
implementations, the accuracy of the transcendental functions is generally a few epsilon. Note however, that the trigonometrical
|
|
functions incur the usual accuracy loss when reducing arguments by large multiples of [pi]. Also note that both __mpf_float
|
|
and __cpp_dec_float have a number of guard digits beyond their stated precision, so the error rates listed for these
|
|
are in some sense artificially low.
|
|
|
|
The following table shows the error rates we observe for these functions with various backend types, functions not listed
|
|
here are exact (tested on Win32 with VC++10, MPFR-3.0.0, MPIR-2.1.1):
|
|
|
|
[table
|
|
[[Function][mpfr_float_50][mpf_float_50][cpp_dec_float_50]]
|
|
[[sqrt][1eps][0eps][0eps]]
|
|
[[exp][1eps][0eps][0eps]]
|
|
[[log][1eps][0eps][0eps]]
|
|
[[log10][1eps][0eps][0eps]]
|
|
[[cos][700eps][0eps][0eps]]
|
|
[[sin][1eps][0eps][0eps]]
|
|
[[tan][0eps][0eps][0eps]]
|
|
[[acos][0eps][0eps][0eps]]
|
|
[[asin][0eps][0eps][0eps]]
|
|
[[atan][1eps][0eps][0eps]]
|
|
[[cosh][1045eps[footnote It's likely that the inherent error in the input values to our test cases are to blame here.]][0eps][0eps]]
|
|
[[sinh][2eps][0eps][0eps]]
|
|
[[tanh][1eps][0eps][0eps]]
|
|
[[pow][0eps][4eps][3eps]]
|
|
[[atan2][1eps][0eps][0eps]]
|
|
]
|
|
[h4 Traits Class Support]
|
|
|
|
template <class T>
|
|
struct component_type;
|
|
|
|
If this is a type with multiple components (for example rational or complex types), then this trait has a single member
|
|
`type` that is the type of those components.
|
|
|
|
template <class T>
|
|
struct number_category;
|
|
|
|
A traits class that inherits from `mpl::int_<N>` where `N` is one of the enumerated values `number_kind_integer`, `number_kind_floating_point`,
|
|
`number_kind_rational`, `number_kind_fixed_point`, or `number_kind_unknown`. This traits class is specialized for any type that has
|
|
`std::numeric_limits` support as well as for classes in this library: which means it can be used for generic code that must work
|
|
with built in arithmetic types as well as multiprecision ones.
|
|
|
|
template <class T>
|
|
struct is_number;
|
|
|
|
A traits class that inherits from `mpl::true_` if T is an instance of `number<>`, otherwise from `mpl::false_`.
|
|
|
|
template <class T>
|
|
struct is_number_expression;
|
|
|
|
A traits class that inherits from `mpl::true_` if T is an expression template type derived from `number<>`, otherwise from `mpl::false_`.
|
|
|
|
|
|
|
|
[h4 Integer functions]
|
|
|
|
In addition to functioning with types from this library, these functions are also overloaded for built in integer
|
|
types if you include `<boost/multiprecision/integer.hpp>`. Further, when used with fixed precision types (whether
|
|
built in integers or multiprecision ones), the functions will promote to a wider type internally when the algorithm
|
|
requires it. Versions overloaded for built in integer types return that integer type rather than an expression
|
|
template.
|
|
|
|
``['unmentionable-expression-template-type]`` gcd(const ``['number-or-expression-template-type]``& a, const ``['number-or-expression-template-type]``& b);
|
|
|
|
Returns the largest integer `x` that divides both `a` and `b`.
|
|
|
|
``['unmentionable-expression-template-type]`` lcm(const ``['number-or-expression-template-type]``& a, const ``['number-or-expression-template-type]``& b);
|
|
|
|
Returns the smallest integer `x` that is divisible by both `a` and `b`.
|
|
|
|
``['unmentionable-expression-template-type]`` pow(const ``['number-or-expression-template-type]``& b, unsigned p);
|
|
|
|
Returns ['b[super p]] as an expression template. Note that this function should be used with extreme care as the result can grow so
|
|
large as to take "effectively forever" to compute, or else simply run the host machine out of memory. This is the one function in
|
|
this category that is not overloaded for built in integer types, further, it's probably not a good idea to use it with
|
|
fixed precision `cpp_int`'s either.
|
|
|
|
``['unmentionable-expression-template-type]`` powm(const ``['number-or-expression-template-type]``& b, const ``['number-or-expression-template-type]``& p, const ``['number-or-expression-template-type]``& m);
|
|
|
|
Returns ['b[super p] mod m] as an expression template. Fixed precision types are promoted internally to ensure accuracy.
|
|
|
|
``['unmentionable-expression-template-type]`` sqrt(const ``['number-or-expression-template-type]``& a);
|
|
|
|
Returns the largest integer `x` such that `x * x < a`.
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
number<Backend, EXpressionTemplates> sqrt(const ``['number-or-expression-template-type]``& a, number<Backend, EXpressionTemplates>& r);
|
|
|
|
Returns the largest integer `x` such that `x * x < a`, and sets the remainder `r` such that `r = a - x * x`.
|
|
|
|
template <class Backend, expression_template_option ExpressionTemplates>
|
|
void divide_qr(const ``['number-or-expression-template-type]``& x, const ``['number-or-expression-template-type]``& y,
|
|
number<Backend, ExpressionTemplates>& q, number<Backend, ExpressionTemplates>& r);
|
|
|
|
Divides x by y and returns both the quotient and remainder. After the call `q = x / y` and `r = x % y`.
|
|
|
|
template <class Integer>
|
|
Integer integer_modulus(const ``['number-or-expression-template-type]``& x, Integer val);
|
|
|
|
Returns the absolute value of `x % val`.
|
|
|
|
unsigned lsb(const ``['number-or-expression-template-type]``& x);
|
|
|
|
Returns the (zero-based) index of the least significant bit that is set to 1.
|
|
|
|
Throws a `std::range_error` if the argument is <= 0.
|
|
|
|
unsigned msb(const ``['number-or-expression-template-type]``& x);
|
|
|
|
Returns the (zero-based) index of the most significant bit.
|
|
|
|
Throws a `std::range_error` if the argument is <= 0.
|
|
|
|
template <class Backend, class ExpressionTemplates>
|
|
bool bit_test(const number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
|
|
Returns `true` if the bit at /index/ in /val/ is set.
|
|
|
|
template <class Backend, class ExpressionTemplates>
|
|
number<Backend, ExpressionTemplates>& bit_set(number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
|
|
Sets the bit at /index/ in /val/, and returns /val/.
|
|
|
|
template <class Backend, class ExpressionTemplates>
|
|
number<Backend, ExpressionTemplates>& bit_unset(number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
|
|
Unsets the bit at /index/ in /val/, and returns /val/.
|
|
|
|
template <class Backend, class ExpressionTemplates>
|
|
number<Backend, ExpressionTemplates>& bit_flip(number<Backend, ExpressionTemplates>& val, unsigned index);
|
|
|
|
Flips the bit at /index/ in /val/, and returns /val/.
|
|
|
|
template <class Engine>
|
|
bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials, Engine& gen);
|
|
bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials);
|
|
|
|
Tests to see if the number /n/ is probably prime - the test excludes the vast majority of composite numbers
|
|
by excluding small prime factors and performing a single Fermat test. Then performs /trials/ Miller-Rabin
|
|
tests. Returns `false` if /n/ is definitely composite, or `true` if /n/ is probably prime with the
|
|
probability of it being composite less than 0.25^trials. Fixed precision types are promoted internally
|
|
to ensure accuracy.
|
|
|
|
[h4 Rational Number Functions]
|
|
|
|
typename component_type<``['number-or-expression-template-type]``>::type numerator (const ``['number-or-expression-template-type]``&);
|
|
typename component_type<``['number-or-expression-template-type]``>::type denominator(const ``['number-or-expression-template-type]``&);
|
|
|
|
These functions return the numerator and denominator of a rational number respectively.
|
|
|
|
[h4 Boost.Math Interoperability Support]
|
|
|
|
namespace boost{ namespace math{
|
|
|
|
int fpclassify (const ``['number-or-expression-template-type]``&, int);
|
|
bool isfinite (const ``['number-or-expression-template-type]``&, int);
|
|
bool isnan (const ``['number-or-expression-template-type]``&, int);
|
|
bool isinf (const ``['number-or-expression-template-type]``&, int);
|
|
bool isnormal (const ``['number-or-expression-template-type]``&, int);
|
|
|
|
}} // namespaces
|
|
|
|
These floating-point classification functions behave exactly as their Boost.Math equivalents.
|
|
|
|
Other Boost.Math functions and templates may also be
|
|
specialized or overloaded to ensure interoperability.
|
|
|
|
[h4 std::numeric_limits support]
|
|
|
|
namespace std{
|
|
|
|
template <class Backend, ExpressionTemplates>
|
|
struct numeric_limits<boost::multiprecision<Backend, ExpressionTemplates> >
|
|
{
|
|
/* Usual members here */
|
|
};
|
|
|
|
}
|
|
|
|
Class template `std::numeric_limits` is specialized for all instantiations of `number` whose precision is known at compile time, plus those
|
|
types whose precision is unlimited (though it is much less useful in those cases). It is not specialized for types
|
|
whose precision can vary at compile time (such as `mpf_float`).
|
|
|
|
[endsect]
|
|
|
|
[section:cpp_int_ref cpp_int]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
typedef unspecified-type limb_type;
|
|
|
|
enum cpp_integer_type { signed_magnitude, unsigned_magnitude };
|
|
enum cpp_int_check_type { checked, unchecked };
|
|
|
|
template <unsigned MinDigits = 0,
|
|
unsigned MaxDits = 0,
|
|
cpp_integer_type SignType = signed_magnitude,
|
|
cpp_int_check_type Checked = unchecked,
|
|
class Allocator = std::allocator<limb_type> >
|
|
class cpp_int_backend;
|
|
//
|
|
// Expression templates default to et_off if there is no allocator:
|
|
//
|
|
template <unsigned MinDigits, unsigned MaxDigits, cpp_integer_type SignType, cpp_int_check_type Checked>
|
|
struct expression_template_default<cpp_int_backend<MinDigits, MaxDigits, SignType, Checked, void> >
|
|
{ static const expression_template_option value = et_off; };
|
|
|
|
typedef number<cpp_int_backend<> > cpp_int; // arbitrary precision integer
|
|
typedef rational_adaptor<cpp_int_backend<> > cpp_rational_backend;
|
|
typedef number<cpp_rational_backend> cpp_rational; // arbitrary precision rational number
|
|
|
|
// Fixed precision unsigned types:
|
|
typedef number<cpp_int_backend<128, 128, unsigned_magnitude, unchecked, void> > uint128_t;
|
|
typedef number<cpp_int_backend<256, 256, unsigned_magnitude, unchecked, void> > uint256_t;
|
|
typedef number<cpp_int_backend<512, 512, unsigned_magnitude, unchecked, void> > uint512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, unsigned_magnitude, unchecked, void> > uint1024_t;
|
|
|
|
// Fixed precision signed types:
|
|
typedef number<cpp_int_backend<128, 128, signed_magnitude, unchecked, void> > int128_t;
|
|
typedef number<cpp_int_backend<256, 256, signed_magnitude, unchecked, void> > int256_t;
|
|
typedef number<cpp_int_backend<512, 512, signed_magnitude, unchecked, void> > int512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, signed_magnitude, unchecked, void> > int1024_t;
|
|
|
|
// Over again, but with checking enabled this time:
|
|
typedef number<cpp_int_backend<0, 0, signed_magnitude, checked> > checked_cpp_int;
|
|
typedef rational_adaptor<cpp_int_backend<0, 0, signed_magnitude, checked> > checked_cpp_rational_backend;
|
|
typedef number<checked_cpp_rational_backend> checked_cpp_rational;
|
|
|
|
// Checked fixed precision unsigned types:
|
|
typedef number<cpp_int_backend<128, 128, unsigned_magnitude, checked, void> > checked_uint128_t;
|
|
typedef number<cpp_int_backend<256, 256, unsigned_magnitude, checked, void> > checked_uint256_t;
|
|
typedef number<cpp_int_backend<512, 512, unsigned_magnitude, checked, void> > checked_uint512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, unsigned_magnitude, checked, void> > checked_uint1024_t;
|
|
|
|
// Fixed precision signed types:
|
|
typedef number<cpp_int_backend<128, 128, signed_magnitude, checked, void> > checked_int128_t;
|
|
typedef number<cpp_int_backend<256, 256, signed_magnitude, checked, void> > checked_int256_t;
|
|
typedef number<cpp_int_backend<512, 512, signed_magnitude, checked, void> > checked_int512_t;
|
|
typedef number<cpp_int_backend<1024, 1024, signed_magnitude, checked, void> > checked_int1024_t;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `cpp_int_backend` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The template arguments are:
|
|
|
|
[variablelist
|
|
[[MinBits][Determines the number of Bits to store directly within the object before resorting to dynamic memory
|
|
allocation. When zero, this field is determined automatically based on how many bits can be stored
|
|
in union with the dynamic storage header: setting a larger value may improve performance as larger integer
|
|
values will be stored internally before memory allocation is required.]]
|
|
[[MaxBits][Determines the maximum number of bits to be stored in the type: resulting in a fixed precision type.
|
|
When this value is the same as MinBits, then the Allocator parameter is ignored, as no dynamic
|
|
memory allocation will ever be performed: in this situation the Allocator parameter should be set to
|
|
type `void`. Note that this parameter should not be used simply to prevent large memory
|
|
allocations, not only is that role better performed by the allocator, but fixed precision
|
|
integers have a tendency to allocate all of MaxBits of storage more often than one would expect.]]
|
|
[[SignType][Determines whether the resulting type is signed or not. Note that for
|
|
[@http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic arbitrary precision] types
|
|
this parameter must be `signed_magnitude`. For fixed precision
|
|
types then this type may be either `signed_magnitude` or `unsigned_magnitude`.]]
|
|
[[Checked][This parameter has two values: `checked` or `unchecked`. See the [link boost_multiprecision.tut.ints.cpp_int tutorial] for more information.]]
|
|
[[Allocator][The allocator to use for dynamic memory allocation, or type `void` if MaxBits == MinBits.]]
|
|
]
|
|
|
|
The type of `number_category<cpp_int<Args...> >::type` is `mpl::int_<number_kind_integer>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.ints.cpp_int tutorial].
|
|
|
|
[endsect]
|
|
|
|
[section:gmp_int_ref gmp_int]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class gmp_int;
|
|
|
|
typedef number<gmp_int > mpz_int;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `gmp_int` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The type of `number_category<cpp_int<Args...> >::type` is `mpl::int_<number_kind_integer>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.ints.gmp_int tutorial].
|
|
|
|
[endsect]
|
|
|
|
[section:tom_int_ref tom_int]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
class tommath_int;
|
|
|
|
typedef number<tommath_int > tom_int;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `tommath_int` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The type of `number_category<cpp_int<Args...> >::type` is `mpl::int_<number_kind_integer>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.ints.tom_int tutorial].
|
|
|
|
[endsect]
|
|
|
|
[section:mpf_ref gmp_float]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10>
|
|
class gmp_float;
|
|
|
|
typedef number<gmp_float<50> > mpf_float_50;
|
|
typedef number<gmp_float<100> > mpf_float_100;
|
|
typedef number<gmp_float<500> > mpf_float_500;
|
|
typedef number<gmp_float<1000> > mpf_float_1000;
|
|
typedef number<gmp_float<0> > mpf_float;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `gmp_float` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The class takes a single template parameter - `Digits10` - which is the number of decimal digits precision the type
|
|
should support. When this parameter is zero, then the precision can be set at runtime via `number::default_precision`
|
|
and `number::precision`. Note that this type does not in any way change the GMP library's global state (for example
|
|
it does not change the default precision of the mpf_t data type), therefore you can safely mix this type with existing
|
|
code that uses GMP, and also mix `gmp_float`s of differing precision.
|
|
|
|
The type of `number_category<cpp_int<Args...> >::type` is `mpl::int_<number_kind_floating_point>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.floats.gmp_float tutorial].
|
|
|
|
[endsect]
|
|
|
|
[section:mpfr_ref mpfr_float_backend]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10>
|
|
class mpfr_float_backend;
|
|
|
|
typedef number<mpfr_float_backend<50> > mpfr_float_50;
|
|
typedef number<mpfr_float_backend<100> > mpfr_float_100;
|
|
typedef number<mpfr_float_backend<500> > mpfr_float_500;
|
|
typedef number<mpfr_float_backend<1000> > mpfr_float_1000;
|
|
typedef number<mpfr_float_backend<0> > mpfr_float;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `mpfr_float_backend` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The class takes a single template parameter - `Digits10` - which is the number of decimal digits precision the type
|
|
should support. When this parameter is zero, then the precision can be set at runtime via `number::default_precision`
|
|
and `number::precision`. Note that this type does not in any way change the GMP or MPFR library's global state (for example
|
|
it does not change the default precision of the mpfr_t data type), therefore you can safely mix this type with existing
|
|
code that uses GMP or MPFR, and also mix `mpfr_float_backend`s of differing precision.
|
|
|
|
The type of `number_category<cpp_int<Args...> >::type` is `mpl::int_<number_kind_floating_point>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.floats.mpfr_float tutorial].
|
|
|
|
[endsect]
|
|
|
|
[section:cpp_bin_float_ref cpp_bin_float]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
enum digit_base_type
|
|
{
|
|
digit_base_2 = 2,
|
|
digit_base_10 = 10
|
|
};
|
|
|
|
template <unsigned Digits, digit_base_type base = digit_base_10, class Allocator = void, class Exponent = int, ExponentMin = 0, ExponentMax = 0>
|
|
class cpp_bin_float;
|
|
|
|
typedef number<cpp_bin_float<50> > cpp_bin_float_50;
|
|
typedef number<cpp_bin_float<100> > cpp_bin_float_100;
|
|
|
|
typedef number<backends::cpp_bin_float<24, backends::digit_base_2, void, boost::int16_t, -126, 127>, et_off> cpp_bin_float_single;
|
|
typedef number<backends::cpp_bin_float<53, backends::digit_base_2, void, boost::int16_t, -1022, 1023>, et_off> cpp_bin_float_double;
|
|
typedef number<backends::cpp_bin_float<64, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_double_extended;
|
|
typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_quad;
|
|
typedef number<backends::cpp_bin_float<237, backends::digit_base_2, void, boost::int32_t, -262142, 262143>, et_off> cpp_bin_float_oct;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `cpp_bin_float` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The class takes six template parameters:
|
|
|
|
[variablelist
|
|
[[Digits][The number of digits precision the type
|
|
should support. This is normally expressed as base-10 digits, but that can be changed via the second template parameter.]]
|
|
[[base][An enumerated value (either `digit_base_10` or `digit_base_2`) that indicates whether `Digits` is base-10 or base-2]]
|
|
[[Allocator][The allocator used: defaults to type `void`, meaning all storage is within the class, and no dynamic
|
|
allocation is performed, but can be set to a standard library allocator if dynamic allocation makes more sense.]]
|
|
[[Exponent][A signed integer type to use as the type of the exponent - defaults to `int`.]]
|
|
[[ExponentMin][The smallest (most negative) permitted exponent, defaults to zero, meaning "define as small as possible
|
|
given the limitations of the type and our internal requirements".]]
|
|
[[ExponentMax][The largest (most positive) permitted exponent, defaults to zero, meaning "define as large as possible
|
|
given the limitations of the type and our internal requirements".]]
|
|
]
|
|
|
|
The type of `number_category<cpp_bin_float<Args...> >::type` is `mpl::int_<number_kind_floating_point>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.floats.cpp_bin_float tutorial].
|
|
|
|
[h4 Implementation Notes]
|
|
|
|
Internally, an N-bit `cpp_bin_float` is represented as an N-bit unsigned integer along with an exponent and a sign.
|
|
The integer part is normalized so that it's most significant bit is always 1. The decimal point is assumed to be
|
|
directly after the most significant bit of the integer part. The special values zero, infinity and NaN all have
|
|
the integer part set to zero, and the exponent to one of 3 special values above the maximum permitted exponent.
|
|
|
|
Multiplication is trivial: multiply the two N-bit integer mantissa's to obtain a 2N-bit number, then round and
|
|
adjust the sign and exponent.
|
|
|
|
Addition and subtraction proceed similarly - if the exponents are such that there is overlap between the two
|
|
values, then left shift the larger value to produce a number with between N and 2N bits, then perform integer
|
|
addition or subtraction, round, and adjust the exponent.
|
|
|
|
Division proceeds as follows: first scale the numerator by some power of 2 so that integer division will
|
|
produce either an N-bit or N+1 bit result plus a remainder. If we get an N bit result then the size of
|
|
twice the remainder compared to the denominator gives us the rounding direction. Otherwise we have one extra bit
|
|
in the result which we can use to determine rounding (in this case ties occur only if the remainder is zero and
|
|
the extra bit is a 1).
|
|
|
|
Square root uses integer square root in a manner analogous to division.
|
|
|
|
Decimal string to binary conversion proceeds as follows: first parse the digits to
|
|
produce an integer multiplied by a decimal exponent. Note that we stop parsing digits
|
|
once we have parsed as many as can possibly effect the result - this stops the integer
|
|
part growing too large when there are a very large number of input digits provided.
|
|
At this stage if the decimal exponent is positive then the result is an integer and we
|
|
can in principle simply multiply by 10^N to get an exact integer result. In practice
|
|
however, that could produce some very large integers. We also need to be able to divide
|
|
by 10^N in the event that the exponent is negative. Therefore calculation of the 10^N
|
|
values plus the multiplication or division are performed using limited precision
|
|
integer arithmetic, plus an exponent, and a track of the accumulated error. At the end of
|
|
the calculation we will either be able to round unambiguously, or the error will be such
|
|
that we can't tell which way to round. In the latter case we simply up the precision and try
|
|
again until we have an unambiguously rounded result.
|
|
|
|
Binary to decimal conversion proceeds very similarly to the above, our aim is to calculate
|
|
`mantissa * 2^shift * 10^E` where `E` is the decimal exponent and `shift` is calculated
|
|
so that the result is an N bit integer assuming we want N digits printed in the result.
|
|
As before we use limited precision arithmetic to calculate the result and up the
|
|
precision as necessary until the result is unambiguously correctly rounded. In addition
|
|
our initial calculation of the decimal exponent may be out by 1, so we have to correct
|
|
that and loop as well in the that case.
|
|
|
|
[endsect]
|
|
|
|
[section:cpp_dec_ref cpp_dec_float]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10, class ExponentType = boost::int32_t, class Allocator = void>
|
|
class cpp_dec_float;
|
|
|
|
typedef number<cpp_dec_float<50> > cpp_dec_float_50;
|
|
typedef number<cpp_dec_float<100> > cpp_dec_float_100;
|
|
|
|
}} // namespaces
|
|
|
|
Class template `cpp_dec_float` fulfils all of the requirements for a [link boost_multiprecision.ref.backendconc Backend] type.
|
|
Its members and non-member functions are deliberately not documented: these are considered implementation details that are subject
|
|
to change.
|
|
|
|
The class takes three template parameters:
|
|
|
|
[variablelist
|
|
[[Digits10][The number of decimal digits precision the type
|
|
should support. Note that this type does not normally perform any dynamic memory allocation, and as a result the `Digits10`
|
|
template argument should not be set too high or the class's size will grow unreasonably large.]]
|
|
[[ExponentType][A signed integer type that represents the exponent of the number]]
|
|
[[Allocator][The allocator used: defaults to type `void`, meaning all storage is within the class, and no dynamic
|
|
allocation is performed, but can be set to a standard library allocator if dynamic allocation makes more sense.]]
|
|
]
|
|
|
|
The type of `number_category<cpp_dec_float<Args...> >::type` is `mpl::int_<number_kind_floating_point>`.
|
|
|
|
More information on this type can be found in the [link boost_multiprecision.tut.floats.cpp_dec_float tutorial].
|
|
|
|
[endsect]
|
|
|
|
[section:internals Internal Support Code]
|
|
|
|
There are some traits classes which authors of new backends should be aware of:
|
|
|
|
namespace boost{ namespace multiprecision{ namespace detail{
|
|
|
|
template<typename From, typename To>
|
|
struct is_explicitly_convertible;
|
|
|
|
}}}
|
|
|
|
Inherits from `boost::integral_constant<bool,true>` if type `From` has an explicit conversion from `To`.
|
|
|
|
For compilers that support C++11 SFINAE-expressions this trait should "just work". Otherwise it inherits
|
|
from `boost::is_convertible<From, To>::type`, and will need to be specialised for Backends that have
|
|
constructors marked as `explicit`.
|
|
|
|
template <class From, class To>
|
|
struct is_lossy_conversion
|
|
{
|
|
static const bool value = see below;
|
|
};
|
|
|
|
Member `value` is true if the conversion from `From` to `To` would result in a loss of precision, and `false` otherwise.
|
|
|
|
The default version of this trait simply checks whether the ['kind] of conversion (for example from a floating-point to an integer type)
|
|
is inherently lossy. Note that if either of the types `From` or `To` are of an unknown number category (because `number_category` is not
|
|
specialised for that type) then this trait will be `true`.
|
|
|
|
template<typename From, typename To>
|
|
struct is_restricted_conversion
|
|
{
|
|
static const bool value = see below;
|
|
};
|
|
|
|
Member `value` is `true` if `From` is only explicitly convertible to `To` and not implicitly convertible, or
|
|
if `is_lossy_conversion<From, To>::value` is `true`. Otherwise `false`.
|
|
|
|
Note that while this trait is the ultimate arbiter of which constructors are marked as `explicit` in class `number`,
|
|
authors of backend types should generally specialise one of the traits above, rather than this one directly.
|
|
|
|
template <class T>
|
|
is_signed_number;
|
|
template <class T>
|
|
is_unsigned_number;
|
|
|
|
These two traits inherit from either `mpl::true_` or `mpl::false_`, by default types are assumed to be signed unless
|
|
`is_unsigned_number` is specialized for that type.
|
|
|
|
[endsect]
|
|
|
|
[section:backendconc Backend Requirements]
|
|
|
|
The requirements on the `Backend` template argument to `number` are split up into
|
|
sections: compulsory and optional.
|
|
|
|
Compulsory requirements have no default implementation in the library, therefore if the feature
|
|
they implement is to be supported at all, then they must be implemented by the backend.
|
|
|
|
Optional requirements have default implementations that are called if the backend doesn't provide
|
|
it's own. Typically the backend will implement these to improve performance.
|
|
|
|
In the following tables, type B is the `Backend` template argument to `number`, `b` and `b2` are
|
|
a variables of type B, `pb` is a variable of type B*, `cb`, `cb2` and `cb3` are constant variables of type `const B`,
|
|
`rb` is a variable of type `B&&`, `a` and `a2` are variables of Arithmetic type,
|
|
`s` is a variable of type `const char*`, `ui` is a variable of type `unsigned`, `bb` is a variable of type `bool`,
|
|
`pa` is a variable of type pointer-to-arithmetic-type, `exp` is a variable of type `B::exp_type`,
|
|
`pexp` is a variable of type `B::exp_type*`, `i` is a variable of type `int`, `pi` pointer to a variable of type `int`,
|
|
B2 is another type that meets these requirements, b2 is a variable of type B2, `ss` is variable of type `std::streamsize`
|
|
and `ff` is a variable of type `std::ios_base::fmtflags`.
|
|
|
|
[table Compulsory Requirements on the Backend type.
|
|
[[Expression][Return Type][Comments][Throws]]
|
|
[[`B::signed_types`][`mpl::list<type-list>`][A list of signed integral types that can be assigned to type B. The types shall be
|
|
listed in order of size, smallest first, and shall terminate in the type that is `std::intmax_t`.][[space]]]
|
|
[[`B::unsigned_types`][`mpl::list<type-list>`][A list of unsigned integral types that can be assigned to type B. The types shall be
|
|
listed in order of size, smallest first, and shall terminate in the type that is `std::uintmax_t`.][[space]]]
|
|
[[`B::float_types`][`mpl::list<type-list>`][A list of floating-point types that can be assigned to type B.The types shall be
|
|
listed in order of size, smallest first, and shall terminate in type `long double`.][[space]]]
|
|
[[`B::exponent_type`][A signed integral type.][The type of the exponent of type B. This type is required only for floating-point types.][[space]]]
|
|
[[`B()`][ ][Default constructor.][[space]]]
|
|
[[`B(cb)`][ ][Copy Constructor.][[space]]]
|
|
[[`b = b`][`B&`][Assignment operator.][[space]]]
|
|
[[`b = a`][`B&`][Assignment from an Arithmetic type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.][[space]]]
|
|
[[`b = s`][`B&`][Assignment from a string.][Throws a `std::runtime_error` if the string could not be interpreted as a valid number.]]
|
|
[[`b.swap(b)`][`void`][Swaps the contents of its arguments.][`noexcept`]]
|
|
[[`cb.str(ss, ff)`][`std::string`][Returns the string representation of `b` with `ss` digits and formatted according to the flags set in `ff`.
|
|
If `ss` is zero, then returns as many digits as are required to reconstruct the original value.][[space]]]
|
|
[[`b.negate()`][`void`][Negates `b`.][[space]]]
|
|
[[`cb.compare(cb2)`][`int`][Compares `cb` and `cb2`, returns a value less than zero if `cb < cb2`, a value greater than zero if `cb > cb2` and zero
|
|
if `cb == cb2`.][`noexcept`]]
|
|
[[`cb.compare(a)`][`int`][Compares `cb` and `a`, returns a value less than zero if `cb < a`, a value greater than zero if `cb > a` and zero
|
|
if `cb == a`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.][[space]]]
|
|
[[`eval_add(b, cb)`][`void`][Adds `cb` to `b`.][[space]]]
|
|
[[`eval_subtract(b, cb)`][`void`][Subtracts `cb` from `b`.][[space]]]
|
|
[[`eval_multiply(b, cb)`][`void`][Multiplies `b` by `cb`.][[space]]]
|
|
[[`eval_divide(b, cb)`][`void`][Divides `b` by `cb`.]
|
|
[`std::overflow_error` if cb has the value zero, and `std::numeric_limits<number<B> >::has_infinity == false`]]
|
|
[[`eval_modulus(b, cb)`][`void`][Computes `b %= cb`, only required when `B` is an integer type.]
|
|
[`std::overflow_error` if cb has the value zero.]]
|
|
[[`eval_bitwise_and(b, cb)`][`void`][Computes `b &= cb`, only required when `B` is an integer type.][[space]]]
|
|
[[`eval_bitwise_or(b, cb)`][`void`][Computes `b |= cb`, only required when `B` is an integer type.][[space]]]
|
|
[[`eval_bitwise_xor(b, cb)`][`void`][Computes `b ^= cb`, only required when `B` is an integer type.][[space]]]
|
|
[[`eval_complement(b, cb)`][`void`][Computes the ones-complement of `cb` and stores the result in `b`, only required when `B` is an integer type.][[space]]]
|
|
[[`eval_left_shift(b, ui)`][`void`][Computes `b <<= ui`, only required when `B` is an integer type.][[space]]]
|
|
[[`eval_right_shift(b, ui)`][`void`][Computes `b >>= ui`, only required when `B` is an integer type.][[space]]]
|
|
[[`eval_convert_to(pa, cb)`][`void`][Converts `cb` to the type of `*pa` and store the result in `*pa`. Type `B` shall support
|
|
conversion to at least types `std::intmax_t`, `std::uintmax_t` and `long long`.
|
|
Conversion to other arithmetic types can then be synthesised using other operations.
|
|
Conversions to other types are entirely optional.][[space]]]
|
|
[[`eval_frexp(b, cb, pexp)`][`void`][Stores values in `b` and `*pexp` such that the value of `cb` is b * 2[super *pexp], only required when `B` is a floating-point type.][[space]]]
|
|
[[`eval_ldexp(b, cb, exp)`][`void`][Stores a value in `b` that is cb * 2[super exp], only required when `B` is a floating-point type.][[space]]]
|
|
[[`eval_frexp(b, cb, pi)`][`void`][Stores values in `b` and `*pi` such that the value of `cb` is b * 2[super *pi], only required when `B` is a floating-point type.]
|
|
[`std::runtime_error` if the exponent of cb is too large to be stored in an `int`.]]
|
|
[[`eval_ldexp(b, cb, i)`][`void`][Stores a value in `b` that is cb * 2[super i], only required when `B` is a floating-point type.][[space]]]
|
|
[[`eval_floor(b, cb)`][`void`][Stores the floor of `cb` in `b`, only required when `B` is a floating-point type.][[space]]]
|
|
[[`eval_ceil(b, cb)`][`void`][Stores the ceiling of `cb` in `b`, only required when `B` is a floating-point type.][[space]]]
|
|
[[`eval_sqrt(b, cb)`][`void`][Stores the square root of `cb` in `b`, only required when `B` is a floating-point type.][[space]]]
|
|
[[`boost::multiprecision::number_category<B>::type`][`mpl::int_<N>`][`N` is one of the values `number_kind_integer`, `number_kind_floating_point`, `number_kind_complex`, `number_kind_rational` or `number_kind_fixed_point`.
|
|
Defaults to `number_kind_floating_point`.][[space]]]
|
|
[[`eval_conj(b, cb)`][`void`][Sets `b` to the complex conjugate of `cb`. Required for complex types only - other types have a sensible default.][[space]]]
|
|
[[`eval_proj(b, cb)`][`void`][Sets `b` to the Riemann projection of `cb`. Required for complex types only - other types have a sensible default.][[space]]]
|
|
[[`eval_real(b, cb)`][`void`][Sets `b` to the real part of `cb`. Required for complex types only - other types have a sensible default.][[space]]]
|
|
[[`eval_imag(b, cb)`][`void`][Sets `b` to the imaginary of `cb`. Required for complex types only - other types have a sensible default.][[space]]]
|
|
[[`eval_set_real(b, a)`][`void`][Sets the real part of `b` to `cb`. Required for complex types only - other types have a sensible default.][[space]]]
|
|
[[`eval_set_imag(b, a)`][`void`][Sets the imaginary part of `b` to `cb`. Required for complex types only - other types have a sensible default.][[space]]]
|
|
]
|
|
|
|
[table Optional Requirements on the Backend Type
|
|
[[Expression][Returns][Comments][Throws]]
|
|
|
|
[[['Construct and assign:]]]
|
|
[[`B(rb)`][`B`][Move constructor. Afterwards variable `rb` shall be in sane state, albeit with unspecified value.
|
|
Only destruction and assignment to the moved-from variable `rb` need be supported after the operation.][`noexcept`]]
|
|
[[`b = rb`][`B&`][Move-assign. Afterwards variable `rb` shall be in sane state, albeit with unspecified value.
|
|
Only destruction and assignment to the moved-from variable `rb` need be supported after the operation.][`noexcept`]]
|
|
[[`B(a)`][`B`][Direct construction from an arithmetic type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, this operation is simulated using default-construction followed by assignment.][[space]]]
|
|
[[`B(b2)`][`B`][Copy constructor from a different back-end type. When not provided, a generic interconversion routine is used.
|
|
This constructor may be `explicit` if the corresponding frontend constructor should also be `explicit`.][[space]]]
|
|
[[`b = b2`][`b&`][Assignment operator from a different back-end type. When not provided, a generic interconversion routine is used.][[space]]]
|
|
[[`assign_components(b, a, a)`][`void`][Assigns to `b` the two components in the following arguments.
|
|
Only applies to rational and complex number types.
|
|
When not provided, arithmetic operations are used to synthesise the result from the two values.][[space]]]
|
|
[[`assign_components(b, b2, b2)`][`void`][Assigns to `b` the two components in the following arguments.
|
|
Only applies to rational and complex number types.
|
|
When not provided, arithmetic operations are used to synthesise the result from the two values.][[space]]]
|
|
|
|
[[['Comparisons:]]]
|
|
[[`eval_eq(cb, cb2)`][`bool`][Returns `true` if `cb` and `cb2` are equal in value.
|
|
When not provided, the default implementation returns `cb.compare(cb2) == 0`.][`noexcept`]]
|
|
[[`eval_eq(cb, a)`][`bool`][Returns `true` if `cb` and `a` are equal in value.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, return the equivalent of `eval_eq(cb, B(a))`.][[space]]]
|
|
[[`eval_eq(a, cb)`][`bool`][Returns `true` if `cb` and `a` are equal in value.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version returns `eval_eq(cb, a)`.][[space]]]
|
|
[[`eval_lt(cb, cb2)`][`bool`][Returns `true` if `cb` is less than `cb2` in value.
|
|
When not provided, the default implementation returns `cb.compare(cb2) < 0`.][`noexcept`]]
|
|
[[`eval_lt(cb, a)`][`bool`][Returns `true` if `cb` is less than `a` in value.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default implementation returns `eval_lt(cb, B(a))`.][[space]]]
|
|
[[`eval_lt(a, cb)`][`bool`][Returns `true` if `a` is less than `cb` in value.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default implementation returns `eval_gt(cb, a)`.][[space]]]
|
|
[[`eval_gt(cb, cb2)`][`bool`][Returns `true` if `cb` is greater than `cb2` in value.
|
|
When not provided, the default implementation returns `cb.compare(cb2) > 0`.][`noexcept`]]
|
|
[[`eval_gt(cb, a)`][`bool`][Returns `true` if `cb` is greater than `a` in value.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default implementation returns `eval_gt(cb, B(a))`.][[space]]]
|
|
[[`eval_gt(a, cb)`][`bool`][Returns `true` if `a` is greater than `cb` in value.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default implementation returns `eval_lt(cb, a)`.][[space]]]
|
|
[[`eval_is_zero(cb)`][`bool`][Returns `true` if `cb` is zero, otherwise `false`. The default version of this function
|
|
returns `cb.compare(ui_type(0)) == 0`, where `ui_type` is `ui_type` is
|
|
`typename mpl::front<typename B::unsigned_types>::type`.][[space]]]
|
|
[[`eval_get_sign(cb)`][`int`][Returns a value < zero if `cb` is negative, a value > zero if `cb` is positive, and zero if `cb` is zero.
|
|
The default version of this function
|
|
returns `cb.compare(ui_type(0))`, where `ui_type` is `ui_type` is
|
|
`typename mpl::front<typename B::unsigned_types>::type`.][[space]]]
|
|
|
|
[[['Basic arithmetic:]]]
|
|
[[`eval_add(b, a)`][`void`][Adds `a` to `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_add(b, B(a))`][[space]]]
|
|
[[`eval_add(b, cb, cb2)`][`void`][Add `cb` to `cb2` and stores the result in `b`.
|
|
When not provided, does the equivalent of `b = cb; eval_add(b, cb2)`.][[space]]]
|
|
[[`eval_add(b, cb, a)`][`void`][Add `cb` to `a` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_add(b, cb, B(a))`.][[space]]]
|
|
[[`eval_add(b, a, cb)`][`void`][Add `a` to `cb` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_add(b, cb, a)`.][[space]]]
|
|
[[`eval_subtract(b, a)`][`void`][Subtracts `a` from `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_subtract(b, B(a))`][[space]]]
|
|
[[`eval_subtract(b, cb, cb2)`][`void`][Subtracts `cb2` from `cb` and stores the result in `b`.
|
|
When not provided, does the equivalent of `b = cb; eval_subtract(b, cb2)`.][[space]]]
|
|
[[`eval_subtract(b, cb, a)`][`void`][Subtracts `a` from `cb` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_subtract(b, cb, B(a))`.][[space]]]
|
|
[[`eval_subtract(b, a, cb)`][`void`][Subtracts `cb` from `a` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_subtract(b, cb, a); b.negate();`.][[space]]]
|
|
[[`eval_multiply(b, a)`][`void`][Multiplies `b` by `a`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_multiply(b, B(a))`][[space]]]
|
|
[[`eval_multiply(b, cb, cb2)`][`void`][Multiplies `cb` by `cb2` and stores the result in `b`.
|
|
When not provided, does the equivalent of `b = cb; eval_multiply(b, cb2)`.][[space]]]
|
|
[[`eval_multiply(b, cb, a)`][`void`][Multiplies `cb` by `a` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_multiply(b, cb, B(a))`.][[space]]]
|
|
[[`eval_multiply(b, a, cb)`][`void`][Multiplies `a` by `cb` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_multiply(b, cb, a)`.][[space]]]
|
|
[[`eval_multiply_add(b, cb, cb2)`][`void`][Multiplies `cb` by `cb2` and adds the result to `b`.
|
|
When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, cb2)` followed by
|
|
`eval_add(b, t)`.][[space]]]
|
|
[[`eval_multiply_add(b, cb, a)`][`void`][Multiplies `a` by `cb` and adds the result to `b`.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, a)` followed by
|
|
`eval_add(b, t)`.][[space]]]
|
|
[[`eval_multiply_add(b, a, cb)`][`void`][Multiplies `a` by `cb` and adds the result to `b`.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided does the equivalent of `eval_multiply_add(b, cb, a)`.][[space]]]
|
|
[[`eval_multiply_subtract(b, cb, cb2)`][`void`][Multiplies `cb` by `cb2` and subtracts the result from `b`.
|
|
When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, cb2)` followed by
|
|
`eval_subtract(b, t)`.][[space]]]
|
|
[[`eval_multiply_subtract(b, cb, a)`][`void`][Multiplies `a` by `cb` and subtracts the result from `b`.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided does the equivalent of creating a temporary `B t` and `eval_multiply(t, cb, a)` followed by
|
|
`eval_subtract(b, t)`.][[space]]]
|
|
[[`eval_multiply_subtract(b, a, cb)`][`void`][Multiplies `a` by `cb` and subtracts the result from `b`.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided does the equivalent of `eval_multiply_subtract(b, cb, a)`.][[space]]]
|
|
[[`eval_multiply_add(b, cb, cb2, cb3)`][`void`][Multiplies `cb` by `cb2` and adds the result to `cb3` storing the result in `b`.
|
|
When not provided does the equivalent of `eval_multiply(b, cb, cb2)` followed by
|
|
`eval_add(b, cb3)`.
|
|
For brevity, only a version showing all arguments of type `B` is shown here, but you can replace up to any 2 of
|
|
`cb`, `cb2` and `cb3` with any type listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.][[space]]]
|
|
[[`eval_multiply_subtract(b, cb, cb2, cb3)`][`void`][Multiplies `cb` by `cb2` and subtracts from the result `cb3` storing the result in `b`.
|
|
When not provided does the equivalent of `eval_multiply(b, cb, cb2)` followed by
|
|
`eval_subtract(b, cb3)`.
|
|
For brevity, only a version showing all arguments of type `B` is shown here, but you can replace up to any 2 of
|
|
`cb`, `cb2` and `cb3` with any type listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.][[space]]]
|
|
[[`eval_divide(b, a)`][`void`][Divides `b` by `a`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_divide(b, B(a))`]
|
|
[`std::overflow_error` if `a` has the value zero, and `std::numeric_limits<number<B> >::has_infinity == false`]]
|
|
[[`eval_divide(b, cb, cb2)`][`void`][Divides `cb` by `cb2` and stores the result in `b`.
|
|
When not provided, does the equivalent of `b = cb; eval_divide(b, cb2)`.]
|
|
[`std::overflow_error` if `cb2` has the value zero, and `std::numeric_limits<number<B> >::has_infinity == false`]]
|
|
[[`eval_divide(b, cb, a)`][`void`][Divides `cb` by `a` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_divide(b, cb, B(a))`.]
|
|
[`std::overflow_error` if `a` has the value zero, and `std::numeric_limits<number<B> >::has_infinity == false`]]
|
|
[[`eval_divide(b, a, cb)`][`void`][Divides `a` by `cb` and stores the result in `b`. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_divide(b, B(a), cb)`.]
|
|
[`std::overflow_error` if cb has the value zero, and `std::numeric_limits<number<B> >::has_infinity == false`]]
|
|
[[`eval_increment(b)`][void][Increments the value of `b` by one.
|
|
When not provided, does the equivalent of `eval_add(b, static_cast<ui_type>(1u))`.
|
|
Where `ui_type` is `typename mpl::front<typename B::unsigned_types>::type`.][[space]]]
|
|
[[`eval_decrement(b)`][void][Decrements the value of `b` by one.
|
|
When not provided, does the equivalent of `eval_subtract(b, static_cast<ui_type>(1u))`.
|
|
Where `ui_type` is `typename mpl::front<typename B::unsigned_types>::type`.][[space]]]
|
|
|
|
[[['Integer specific operations:]]]
|
|
[[`eval_modulus(b, a)`][`void`][Computes `b %= cb`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_modulus(b, B(a))`]
|
|
[`std::overflow_error` if `a` has the value zero.]]
|
|
[[`eval_modulus(b, cb, cb2)`][`void`][Computes `cb % cb2` and stores the result in `b`, only required when `B` is an integer type.
|
|
When not provided, does the equivalent of `b = cb; eval_modulus(b, cb2)`.]
|
|
[`std::overflow_error` if `a` has the value zero.]]
|
|
[[`eval_modulus(b, cb, a)`][`void`][Computes `cb % a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_modulus(b, cb, B(a))`.]
|
|
[`std::overflow_error` if `a` has the value zero.]]
|
|
[[`eval_modulus(b, a, cb)`][`void`][Computes `cb % a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_modulus(b, B(a), cb)`.]
|
|
[`std::overflow_error` if `a` has the value zero.]]
|
|
[[`eval_bitwise_and(b, a)`][`void`][Computes `b &= cb`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_bitwise_and(b, B(a))`][[space]]]
|
|
[[`eval_bitwise_and(b, cb, cb2)`][`void`][Computes `cb & cb2` and stores the result in `b`, only required when `B` is an integer type.
|
|
When not provided, does the equivalent of `b = cb; eval_bitwise_and(b, cb2)`.][[space]]]
|
|
[[`eval_bitwise_and(b, cb, a)`][`void`][Computes `cb & a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_bitwise_and(b, cb, B(a))`.][[space]]]
|
|
[[`eval_bitwise_and(b, a, cb)`][`void`][Computes `cb & a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_bitwise_and(b, cb, a)`.][[space]]]
|
|
[[`eval_bitwise_or(b, a)`][`void`][Computes `b |= cb`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_bitwise_or(b, B(a))`][[space]]]
|
|
[[`eval_bitwise_or(b, cb, cb2)`][`void`][Computes `cb | cb2` and stores the result in `b`, only required when `B` is an integer type.
|
|
When not provided, does the equivalent of `b = cb; eval_bitwise_or(b, cb2)`.][[space]]]
|
|
[[`eval_bitwise_or(b, cb, a)`][`void`][Computes `cb | a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_bitwise_or(b, cb, B(a))`.][[space]]]
|
|
[[`eval_bitwise_or(b, a, cb)`][`void`][Computes `cb | a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_bitwise_or(b, cb, a)`.][[space]]]
|
|
[[`eval_bitwise_xor(b, a)`][`void`][Computes `b ^= cb`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, the default version calls `eval_bitwise_xor(b, B(a))`][[space]]]
|
|
[[`eval_bitwise_xor(b, cb, cb2)`][`void`][Computes `cb ^ cb2` and stores the result in `b`, only required when `B` is an integer type.
|
|
When not provided, does the equivalent of `b = cb; eval_bitwise_xor(b, cb2)`.][[space]]]
|
|
[[`eval_bitwise_xor(b, cb, a)`][`void`][Computes `cb ^ a` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_bitwise_xor(b, cb, B(a))`.][[space]]]
|
|
[[`eval_bitwise_xor(b, a, cb)`][`void`][Computes `a ^ cb` and stores the result in `b`, only required when `B` is an integer type. The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
When not provided, does the equivalent of `eval_bitwise_xor(b, cb, a)`.][[space]]]
|
|
[[`eval_left_shift(b, cb, ui)`][`void`][Computes `cb << ui` and stores the result in `b`, only required when `B` is an integer type.
|
|
When not provided, does the equivalent of `b = cb; eval_left_shift(b, a);`.][[space]]]
|
|
[[`eval_right_shift(b, cb, ui)`][`void`][Computes `cb >> ui` and stores the result in `b`, only required when `B` is an integer type.
|
|
When not provided, does the equivalent of `b = cb; eval_right_shift(b, a);`.][[space]]]
|
|
[[`eval_qr(cb, cb2, b, b2)`][`void`][Sets `b` to the result of `cb / cb2` and `b2` to the result of `cb % cb2`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.]
|
|
[`std::overflow_error` if `a` has the value zero.]]
|
|
[[`eval_integer_modulus(cb, ui)`][`unsigned`][Returns the result of `cb % ui`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.]
|
|
[`std::overflow_error` if `a` has the value zero.]]
|
|
[[`eval_lsb(cb)`][`unsigned`][Returns the index of the least significant bit that is set. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_msb(cb)`][`unsigned`][Returns the index of the most significant bit that is set. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_bit_test(cb, ui)`][`bool`][Returns true if `cb` has bit `ui` set. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_bit_set(b, ui)`][`void`][Sets the bit at index `ui` in `b`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_bit_unset(b, ui)`][`void`][Unsets the bit at index `ui` in `b`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_bit_flip(b, ui)`][`void`][Flips the bit at index `ui` in `b`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_gcd(b, cb, cb2)`][`void`][Sets `b` to the greatest common divisor of `cb` and `cb2`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_lcm(b, cb, cb2)`][`void`][Sets `b` to the least common multiple of `cb` and `cb2`. Only required when `B` is an integer type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_gcd(b, cb, a)`][`void`][Sets `b` to the greatest common divisor of `cb` and `cb2`. Only required when `B` is an integer type.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
The default version of this function calls `eval_gcd(b, cb, B(a))`.][[space]]]
|
|
[[`eval_lcm(b, cb, a)`][`void`][Sets `b` to the least common multiple of `cb` and `cb2`. Only required when `B` is an integer type.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
The default version of this function calls `eval_lcm(b, cb, B(a))`.][[space]]]
|
|
[[`eval_gcd(b, a, cb)`][`void`][Sets `b` to the greatest common divisor of `cb` and `a`. Only required when `B` is an integer type.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
The default version of this function calls `eval_gcd(b, cb, a)`.][[space]]]
|
|
[[`eval_lcm(b, a, cb)`][`void`][Sets `b` to the least common multiple of `cb` and `a`. Only required when `B` is an integer type.
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types` or `B::float_types`.
|
|
The default version of this function calls `eval_lcm(b, cb, a)`.][[space]]]
|
|
[[`eval_powm(b, cb, cb2, cb3)`][`void`][Sets `b` to the result of ['(cb^cb2)%cb3].
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_powm(b, cb, cb2, a)`][`void`][Sets `b` to the result of ['(cb^cb2)%a].
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types`.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_powm(b, cb, a, cb2)`][`void`][Sets `b` to the result of ['(cb^a)%cb2].
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types`.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_powm(b, cb, a, a2)`][`void`][Sets `b` to the result of ['(cb^a)%a2].
|
|
The type of `a` shall be listed in one of the type lists
|
|
`B::signed_types`, `B::unsigned_types`.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_integer_sqrt(b, cb, b2)`][`void`][Sets `b` to the largest integer which when squared is less than `cb`, also
|
|
sets `b2` to the remainder, ie to ['cb - b[super 2]].
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
|
|
[[['Sign manipulation:]]]
|
|
[[`eval_abs(b, cb)`][`void`][Set `b` to the absolute value of `cb`.
|
|
The default version of this functions assigns `cb` to `b`, and then calls `b.negate()` if
|
|
`eval_get_sign(cb) < 0`.][[space]]]
|
|
[[`eval_fabs(b, cb)`][`void`][Set `b` to the absolute value of `cb`.
|
|
The default version of this functions assigns `cb` to `b`, and then calls `b.negate()` if
|
|
`eval_get_sign(cb) < 0`.][[space]]]
|
|
|
|
[[['floating-point functions:]]]
|
|
[[`eval_fpclassify(cb)`][`int`][Returns one of the same values returned by `std::fpclassify`. Only required when `B` is an floating-point type.
|
|
The default version of this function will only test for zero `cb`.][[space]]]
|
|
[[`eval_trunc(b, cb)`][`void`][Performs the equivalent operation to `std::trunc` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_round(b, cb)`][`void`][Performs the equivalent operation to `std::round` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_exp(b, cb)`][`void`][Performs the equivalent operation to `std::exp` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_exp2(b, cb)`][`void`][Performs the equivalent operation to `std::exp2` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is implemented in terms of `eval_pow`.][[space]]]
|
|
[[`eval_log(b, cb)`][`void`][Performs the equivalent operation to `std::log` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_log10(b, cb)`][`void`][Performs the equivalent operation to `std::log10` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_sin(b, cb)`][`void`][Performs the equivalent operation to `std::sin` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_cos(b, cb)`][`void`][Performs the equivalent operation to `std::cos` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_tan(b, cb)`][`void`][Performs the equivalent operation to `std::exp` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_asin(b, cb)`][`void`][Performs the equivalent operation to `std::asin` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_acos(b, cb)`][`void`][Performs the equivalent operation to `std::acos` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_atan(b, cb)`][`void`][Performs the equivalent operation to `std::atan` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_sinh(b, cb)`][`void`][Performs the equivalent operation to `std::sinh` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_cosh(b, cb)`][`void`][Performs the equivalent operation to `std::cosh` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_tanh(b, cb)`][`void`][Performs the equivalent operation to `std::tanh` on argument `cb` and stores the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_fmod(b, cb, cb2)`][`void`][Performs the equivalent operation to `std::fmod` on arguments `cb` and `cb2`, and store the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_modf(b, cb, pb)`][`void`][Performs the equivalent operation to `std::modf` on argument `cb`, and store the integer result in `*pb` and the fractional part in `b`.
|
|
Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_pow(b, cb, cb2)`][`void`][Performs the equivalent operation to `std::pow` on arguments `cb` and `cb2`, and store the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_atan2(b, cb, cb2)`][`void`][Performs the equivalent operation to `std::atan` on arguments `cb` and `cb2`, and store the result in `b`. Only required when `B` is an floating-point type.
|
|
The default version of this function is synthesised from other operations above.][[space]]]
|
|
[[`eval_scalbn(b, cb, e)`][`void`][Scales value `cb` by ['r[super e]], where ['r] is the radix of the type. The default version of this function
|
|
is implemented in terms of eval_ldexp, consequently this function must be provided for types with a radix other than 2.]]
|
|
[[`eval_scalbln(b, cb, e)`][`void`][Calls `eval_scalbn(b, cb, e)`.]]
|
|
[[`eval_ilogb(cb)`][`B::exponent_type`][Returns the exponent ['e] of value `cb` such that ['1 <= cb*r[super -e] < r], where ['r] is the radix of type B.
|
|
The default version of this function is implemented in terms of eval_frexp, consequently this function must be provided for types with a radix other than 2.]]
|
|
[[`eval_remquo(b, cb, cb2, pi)`][`void`][Sets `b = cb - n * cb2` and stores `n` in `*pi`.]]
|
|
[[`eval_remquo(b, cb, a, pi)`][`void`][Default version converts a to type B and calls the overload above.]]
|
|
[[`eval_remquo(b, a, cb, pi)`][`void`][Default version converts a to type B and calls the overload above.]]
|
|
[[`eval_remainder(b, cb, cb2)`][`void`][Default version calls eval_remquo with a dummy final argument.]]
|
|
[[`eval_remainder(b, cb, a)`][`void`][Default version calls eval_remquo with a dummy final argument.]]
|
|
[[`eval_remainder(b, a, cb)`][`void`][Default version calls eval_remquo with a dummy final argument.]]
|
|
|
|
[[`eval_fdim(b, cb, cb2)`][`void`][Default version sets `b = cb - cb2` if `cb > cb2` and zero otherwise. Special cases are handled as in the C99 annex.]]
|
|
[[`eval_fdim(b, cb, a)`][`void`][Default version sets `b = cb - cb2` if `cb > cb2` and zero otherwise. Special cases are handled as in the C99 annex.]]
|
|
[[`eval_fdim(b, a, cb)`][`void`][Default version sets `b = cb - cb2` if `cb > cb2` and zero otherwise. Special cases are handled as in the C99 annex.]]
|
|
|
|
[[`eval_fmax(b, cb, cb2)`][`void`][Sets `b` to the larger of `cb` and `cb2`.]]
|
|
[[`eval_fmax(b, cb, a)`][`void`][Sets `b` to the larger of `cb` and `a`.]]
|
|
[[`eval_fmax(b, a, cb)`][`void`][Sets `b` to the larger of `cb` and `a`.]]
|
|
[[`eval_fmin(b, cb, cb2)`][`void`][Sets `b` to the smaller of `cb` and `cb2`.]]
|
|
[[`eval_fmin(b, cb, a)`][`void`][Sets `b` to the smaller of `cb` and `a`.]]
|
|
[[`eval_fmin(b, a, cb)`][`void`][Sets `b` to the smaller of `cb` and `a`.]]
|
|
|
|
[[`eval_hypot(b, cb, cb2)`][`void`][Sets `b` to the square root of the sum of the squares of `cb` and `cb2` without undue over or under flow.]]
|
|
[[`eval_hypot(b, cb, a)`][`void`][As above.]]
|
|
[[`eval_hypot(b, a, cb)`][`void`][As above.]]
|
|
|
|
[[`eval_logb(b, cb)`][`B::exponent_type`][Sets `b` to the exponent ['e] of value `cb` such that ['1 <= cb*r[super -b] < r], where ['r] is the radix of type B.
|
|
The default version of this function is implemented in terms of `eval_ilogb`.]]
|
|
[[`eval_nearbyint(b, cb)`][`void`][Calls `eval_round(b, cb)`.]]
|
|
[[`eval_rint(b, cb)`][`void`][Calls `eval_nearbyint(b, cb)`.]]
|
|
[[`eval_log2(b, cb)`][`void`][Sets `b` to the logarithm base 2 of `cb`.]]
|
|
|
|
[[['hashing:]]]
|
|
[[`hash_value(cb)`][`std::size_t`]
|
|
[Returns a hash value for the argument that is suitable for use with `std::hash` etc. If not provided then no automatic hashing support will be available for the number type.]]
|
|
]
|
|
|
|
When the tables above place no ['throws] requirements on an operation, then it is up to each type modelling this concept to
|
|
decide when or whether throwing an exception is desirable. However, thrown exceptions should always either be the type, or
|
|
inherit from the type `std::runtime_error`. For example, a floating-point type might choose to throw `std::overflow_error`
|
|
whenever the result of an operation would be infinite, and `std::underflow_error` whenever it would round to zero.
|
|
|
|
[note
|
|
The non-member functions are all named with an "eval_" prefix to avoid conflicts with template classes of the same name -
|
|
in point of fact this naming convention shouldn't be necessary, but rather works around some compiler bugs.]
|
|
|
|
[h4 Overloadable Functions]
|
|
|
|
Some of the C99 math functions do not have `eval_` functions but must be overloaded directly: these functions
|
|
are either trivial or are forwarded to the Boost.Math implementations by default.
|
|
The full list of these functions is:
|
|
|
|
int sign (const ``['number-or-expression-template-type]``&);
|
|
int signbit (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` changesign (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` copysign (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` asinh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` acosh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` atanh (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` cbrt (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` erf (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` erfc (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` expm1 (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` log1p (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` tgamma (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` lgamma (const ``['number-or-expression-template-type]``&);
|
|
long lrint (const ``['number-or-expression-template-type]``&);
|
|
long long llrint (const ``['number-or-expression-template-type]``&);
|
|
``['number]`` nextafter (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
``['number]`` nexttoward (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
|
|
|
|
[endsect]
|
|
|
|
[section:headers Header File Structure]
|
|
|
|
[table Top level headers
|
|
[[Header][Contains]]
|
|
[[cpp_int.hpp][The `cpp_int` backend type.]]
|
|
[[gmp.hpp][Defines all [gmp] related backends.]]
|
|
[[miller_rabin.hpp][Miller Rabin primality testing code.]]
|
|
[[number.hpp][Defines the `number` backend, is included by all the backend headers.]]
|
|
[[mpfr.hpp][Defines the mpfr_float_backend backend.]]
|
|
[[random.hpp][Defines code to interoperate with Boost.Random.]]
|
|
[[rational_adaptor.hpp][Defines the `rational_adaptor` backend.]]
|
|
[[cpp_dec_float.hpp][Defines the `cpp_dec_float` backend.]]
|
|
[[tommath.hpp][Defines the `tommath_int` backend.]]
|
|
[[concepts/number_archetypes.hpp][Defines a backend concept archetypes for testing use.]]
|
|
]
|
|
|
|
[table Implementation Headers
|
|
[[Header][Contains]]
|
|
[[cpp_int/add.hpp][Add and subtract operators for `cpp_int_backend`.]]
|
|
[[cpp_int/bitwise.hpp][Bitwise operators for `cpp_int_backend`.]]
|
|
[[cpp_int/checked.hpp][Helper functions for checked arithmetic for `cpp_int_backend`.]]
|
|
[[cpp_int/comparison.hpp][Comparison operators for `cpp_int_backend`.]]
|
|
[[cpp_int/cpp_int_config.hpp][Basic setup and configuration for `cpp_int_backend`.]]
|
|
[[cpp_int/divide.hpp][Division and modulus operators for `cpp_int_backend`.]]
|
|
[[cpp_int/limits.hpp][`numeric_limits` support for `cpp_int_backend`.]]
|
|
[[cpp_int/misc.hpp][Miscellaneous operators for `cpp_int_backend`.]]
|
|
[[cpp_int/multiply.hpp][Multiply operators for `cpp_int_backend`.]]
|
|
[[detail/big_lanczos.hpp][Lanczos support for Boost.Math integration.]]
|
|
[[detail/default_ops.hpp][Default versions of the optional backend non-member functions.]]
|
|
[[detail/generic_interconvert.hpp][Generic interconversion routines.]]
|
|
[[detail/number_base.hpp][All the expression template code, metaprogramming, and operator overloads for `number`.]]
|
|
[[detail/no_et_ops.hpp][The non-expression template operators.]]
|
|
[[detail/functions/constants.hpp][Defines constants used by the floating-point functions.]]
|
|
[[detail/functions/pow.hpp][Defines default versions of the power and exponential related floating-point functions.]]
|
|
[[detail/functions/trig.hpp][Defines default versions of the trigonometric related floating-point functions.]]
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:perf Performance Comparison]
|
|
|
|
[section:overhead The Overhead in the Number Class Wrapper]
|
|
|
|
Using a simple [@../../performance/arithmetic_backend.hpp backend class] that wraps any built in arithmetic type
|
|
we can measure the overhead involved in wrapping a type inside the `number` frontend, and the effect that turning
|
|
on expression templates has. The following table compares the performance between `double` and a `double` wrapped
|
|
inside class `number`:
|
|
|
|
[table
|
|
[[Type][Bessel Function Evaluation][Non-Central T Evaluation]]
|
|
[[`double`] [[*1.0 (0.016s)]] [[*1.0] (0.46s)]]
|
|
[[`number<arithmetic_backend<double>, et_off>`] [1.2 (0.019s)] [[*1.0](0.46s)]]
|
|
[[`number<arithmetic_backend<double>, et_on>`] [1.2 (0.019s)] [1.7 (0.79s)]]
|
|
]
|
|
|
|
As you can see whether or not there is an overhead, and how large it is depends on the actual situation,
|
|
but the overhead is in any cases small. Expression templates generally add a greater overhead the
|
|
more complex the expression becomes due to the logic of figuring out how to best unpack and evaluate
|
|
the expression, but of course this is also the situation where you save more temporaries. For a
|
|
"trivial" backend like this, saving temporaries has no benefit, but for larger types it becomes
|
|
a bigger win.
|
|
|
|
The following table compares arithmetic using either `long long` or `number<arithmetic_backend<long long> >`
|
|
for the [@../../performance/voronoi_performance.cpp voronoi-diagram builder test]:
|
|
|
|
[table
|
|
[[Type][Relative time]]
|
|
[[`long long`][[*1.0](0.0823s)]]
|
|
[[`number<arithmetic_backend<long long>, et_off>`][1.05 (0.0875s)]]
|
|
]
|
|
|
|
This test involves mainly creating a lot of temporaries and performing a small amount of arithmetic on them,
|
|
with very little difference in performance between the native and "wrapped" types.
|
|
|
|
The test code was compiled with Microsoft Visual Studio 2010 with all optimisations
|
|
turned on (/Ox), and used MPIR-2.3.0 and [tommath]-0.42.0. The tests were run on 32-bit
|
|
Windows Vista machine.
|
|
|
|
[endsect]
|
|
|
|
[section:realworld Floating-Point Real World Tests]
|
|
|
|
These tests test the total time taken to execute all of Boost.Math's test cases for these functions.
|
|
In each case the best performing library gets a relative score of 1, with the total execution time
|
|
given in brackets. The first three libraries listed are the various floating-point types provided
|
|
by this library, while for comparison, two popular C++ front-ends to [mpfr] ([mpfr_class] and [mpreal])
|
|
are also shown.
|
|
|
|
[table Bessel Function Performance
|
|
[[Library][50 Decimal Digits][100 Decimal Digits]]
|
|
[[mpfr_float] [1.2 (5.78s)] [1.2 (9.56s)]]
|
|
[[static_mpfr_float] [1.1 (5.47s)] [1.1 (9.09s)]]
|
|
[[mpf_float] [[*1.0] (4.82s)] [[*1.0](8.07s)]]
|
|
[[cpp_dec_float] [1.8 (8.54s)] [2.6 (20.66s)]]
|
|
[[[mpfr_class]] [1.3 (6.28s)] [1.2(10.06s)]]
|
|
[[[mpreal]] [2.0 (9.54s)] [1.7 (14.08s)]]
|
|
]
|
|
|
|
[table Non-Central T Distribution Performance
|
|
[[Library][50 Decimal Digits]]
|
|
[[mpfr_float] [1.3 (263.27s)]]
|
|
[[static_mpfr_float] [1.2 (232.88s)]]
|
|
[[mpf_float] [[*1.0] (195.73s)]]
|
|
[[cpp_dec_float] [1.9 (366.38s)]]
|
|
[[[mpfr_class]] [1.5 (286.94s)]]
|
|
[[[mpreal]] [2.0 (388.70s)]]
|
|
]
|
|
|
|
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations
|
|
turned on (/Ox), and used MPIR-2.3.0 and [mpfr]-3.0.0. The tests were run on 32-bit
|
|
Windows Vista machine.
|
|
|
|
[endsect]
|
|
|
|
[section:int_real_world Integer Real World Tests]
|
|
|
|
The first set of [@../../performance/voronoi_performance.cpp tests] measure the times taken to
|
|
execute the multiprecision part of the Voronoi-diagram builder from Boost.Polygon. The tests
|
|
mainly create a large number of temporaries "just in case" multiprecision arithmetic is required,
|
|
for comparison, also included in the tests is Boost.Polygon's own partial-multiprecision integer
|
|
type which was custom written for this specific task:
|
|
|
|
[table
|
|
[[Integer Type][Relative Performance (Actual time in parenthesis)]]
|
|
[[polygon::detail::extended_int][1(0.138831s)]]
|
|
[[int256_t][1.19247(0.165551s)]]
|
|
[[int512_t][1.23301(0.17118s)]]
|
|
[[int1024_t][1.21463(0.168628s)]]
|
|
[[checked_int256_t][1.31711(0.182855s)]]
|
|
[[checked_int512_t][1.57413(0.218538s)]]
|
|
[[checked_int1024_t][1.36992(0.190187s)]]
|
|
[[cpp_int][1.63244(0.226632s)]]
|
|
[[mpz_int][5.42511(0.753172s)]]
|
|
[[tom_int][29.0793(4.03709s)]]
|
|
]
|
|
|
|
Note how for this use case, any dynamic allocation is a performance killer.
|
|
|
|
The next [@../../performance/miller_rabin_performance.cpp tests] measure the time taken to generate 1000 128-bit
|
|
random numbers and test for primality using the Miller Rabin test. This is primarily a test of modular-exponentiation
|
|
since that is the rate limiting step:
|
|
|
|
[table
|
|
[[Integer Type][Relative Performance (Actual time in parenthesis)]]
|
|
[[cpp_int][5.25827(0.379597s)]]
|
|
[[cpp_int (no Expression templates)][5.15675(0.372268s)]]
|
|
[[cpp_int (128-bit cache)][5.10882(0.368808s)]]
|
|
[[cpp_int (256-bit cache)][5.50623(0.397497s)]]
|
|
[[cpp_int (512-bit cache)][4.82257(0.348144s)]]
|
|
[[cpp_int (1024-bit cache)][5.00053(0.360991s)]]
|
|
[[int1024_t][4.37589(0.315897s)]]
|
|
[[checked_int1024_t][4.52396(0.326587s)]]
|
|
[[mpz_int][1(0.0721905s)]]
|
|
[[mpz_int (no Expression templates)][1.0248(0.0739806s)]]
|
|
[[tom_int][2.60673(0.188181s)]]
|
|
[[tom_int (no Expression templates)][2.64997(0.191303s)]]
|
|
]
|
|
|
|
It's interesting to note that expression templates have little effect here - perhaps because the actual expressions involved
|
|
are relatively trivial in this case - so the time taken for multiplication and division tends to dominate. Also note
|
|
how increasing the internal cache size used by `cpp_int` is quite effective in this case in cutting out memory allocations
|
|
altogether - cutting about a third off the total runtime. Finally the much quicker times from GMP and tommath are down to their
|
|
much better modular-exponentiation algorithms (GMP's is about 5x faster). That's an issue which needs to be addressed
|
|
in a future release for __cpp_int.
|
|
|
|
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations
|
|
turned on (/Ox), and used MPIR-2.3.0 and [mpfr]-3.0.0. The tests were run on 32-bit
|
|
Windows Vista machine.
|
|
|
|
[endsect]
|
|
|
|
[section:float_performance Float Algorithm Performance]
|
|
|
|
Note that these tests are carefully designed to test performance of the underlying algorithms
|
|
and not memory allocation or variable copying. As usual, performance results should be taken
|
|
with a healthy dose of scepticism, and real-world performance may vary widely depending upon the
|
|
specifics of the program. In each table relative times are given first, with the best performer
|
|
given a score of 1. Total actual times are given in brackets, measured in seconds for 500000
|
|
operations.
|
|
|
|
[table Operator +
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.0575156s)][[*1] (0.0740086s)][[*1] (0.219073s)]]
|
|
[[gmp_float][2.45065 (0.14095s)][2.01398 (0.149052s)][1.09608 (0.240122s)]]
|
|
[[mpfr_float][2.6001 (0.149546s)][2.12079 (0.156957s)][1.09078 (0.23896s)]]
|
|
]
|
|
[table Operator +(int)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][1.46115 (0.0855392s)][2.60353 (0.114398s)][3.62562 (0.264905s)]]
|
|
[[gmp_float][[*1] (0.0585424s)][[*1] (0.0439398s)][[*1] (0.0730648s)]]
|
|
[[mpfr_float][2.40441 (0.14076s)][3.2877 (0.144461s)][2.40379 (0.175632s)]]
|
|
]
|
|
[table Operator +(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.118146s)][[*1] (0.144714s)][[*1] (0.315639s)]]
|
|
[[gmp_float][4.5555 (0.538213s)][3.83096 (0.554395s)][1.95079 (0.615745s)]]
|
|
[[mpfr_float][5.74477 (0.678719s)][4.85295 (0.702291s)][2.70354 (0.853342s)]]
|
|
]
|
|
[table Operator +=(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.101188s)][[*1] (0.122394s)][[*1] (0.251975s)]]
|
|
[[gmp_float][5.199 (0.526079s)][4.39327 (0.537712s)][2.42151 (0.610159s)]]
|
|
[[mpfr_float][6.08318 (0.615547s)][5.18525 (0.634645s)][3.1022 (0.781677s)]]
|
|
]
|
|
[table Operator -
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.0895163s)][[*1] (0.129248s)][1.5088 (0.374512s)]]
|
|
[[gmp_float][1.72566 (0.154474s)][1.22567 (0.158415s)][[*1] (0.248219s)]]
|
|
[[mpfr_float][1.83764 (0.164499s)][1.34284 (0.173559s)][1.00226 (0.248781s)]]
|
|
]
|
|
[table Operator -(int)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.105285s)][[*1] (0.142741s)][[*1] (0.278718s)]]
|
|
[[gmp_float][2.34437 (0.246828s)][1.28814 (0.183871s)][1.00731 (0.280754s)]]
|
|
[[mpfr_float][2.8032 (0.295136s)][2.09178 (0.298582s)][1.25213 (0.34899s)]]
|
|
]
|
|
[table Operator -(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.13719s)][[*1] (0.184428s)][[*1] (0.344212s)]]
|
|
[[gmp_float][4.0804 (0.559791s)][3.06776 (0.565781s)][2.07736 (0.715053s)]]
|
|
[[mpfr_float][5.10114 (0.699828s)][3.88684 (0.716843s)][2.50074 (0.860784s)]]
|
|
]
|
|
[table Operator -=(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.100984s)][[*1] (0.123148s)][[*1] (0.246181s)]]
|
|
[[gmp_float][5.68353 (0.573944s)][4.68636 (0.577116s)][2.6958 (0.663655s)]]
|
|
[[mpfr_float][6.19738 (0.625834s)][5.18544 (0.638577s)][3.18738 (0.784673s)]]
|
|
]
|
|
[table Operator *
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][1.03667 (0.284251s)][1.30576 (0.536527s)][1.44686 (4.81057s)]]
|
|
[[gmp_float][[*1] (0.274196s)][[*1] (0.410891s)][[*1] (3.32484s)]]
|
|
[[mpfr_float][1.24537 (0.341477s)][1.15785 (0.475749s)][1.1796 (3.92199s)]]
|
|
]
|
|
[table Operator *(int)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][3.97453 (0.240262s)][9.91222 (0.463473s)][50.7926 (4.36527s)]]
|
|
[[gmp_float][[*1] (0.0604505s)][[*1] (0.0467577s)][[*1] (0.0859431s)]]
|
|
[[mpfr_float][2.56974 (0.155342s)][3.56312 (0.166603s)][3.22964 (0.277565s)]]
|
|
]
|
|
[table Operator *(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.331877s)][1.01058 (0.586122s)][6.688 (4.7931s)]]
|
|
[[gmp_float][1.72433 (0.572266s)][[*1] (0.579987s)][[*1] (0.716672s)]]
|
|
[[mpfr_float][2.5553 (0.848047s)][1.74987 (1.0149s)][1.80403 (1.2929s)]]
|
|
]
|
|
[table Operator *=(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.321397s)][1.00772 (0.574887s)][6.65946 (4.7468s)]]
|
|
[[gmp_float][1.77419 (0.570218s)][[*1] (0.570482s)][[*1] (0.712791s)]]
|
|
[[mpfr_float][2.62172 (0.842611s)][1.77691 (1.01369s)][1.77511 (1.26528s)]]
|
|
]
|
|
[table Operator /
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][2.96096 (4.00777s)][4.53244 (7.86435s)][6.11936 (51.5509s)]]
|
|
[[gmp_float][[*1] (1.35354s)][[*1] (1.73512s)][[*1] (8.42422s)]]
|
|
[[mpfr_float][1.30002 (1.75963s)][1.39045 (2.41261s)][1.66762 (14.0484s)]]
|
|
]
|
|
[table Operator /(int)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][8.60726 (1.8181s)][15.4122 (3.67479s)][34.5119 (24.729s)]]
|
|
[[gmp_float][1.24394 (0.262756s)][[*1] (0.238433s)][[*1] (0.716536s)]]
|
|
[[mpfr_float][[*1] (0.211229s)][1.12178 (0.26747s)][1.02237 (0.732562s)]]
|
|
]
|
|
[table Operator /(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][2.10976 (1.97569s)][3.73601 (3.9133s)][11.3085 (25.4533s)]]
|
|
[[gmp_float][[*1] (0.936452s)][[*1] (1.04746s)][[*1] (2.25081s)]]
|
|
[[mpfr_float][1.3423 (1.257s)][1.51575 (1.58768s)][3.31513 (7.46175s)]]
|
|
]
|
|
[table Operator /=(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][2.17401 (1.96883s)][3.79591 (3.8965s)][11.2328 (25.2606s)]]
|
|
[[gmp_float][[*1] (0.905621s)][[*1] (1.0265s)][[*1] (2.24882s)]]
|
|
[[mpfr_float][1.37953 (1.24933s)][1.53073 (1.57129s)][3.30546 (7.43339s)]]
|
|
]
|
|
[table Operator construct
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.00929804s)][[*1] (0.0268321s)][[*1] (0.0310685s)]]
|
|
[[gmp_float][30.8781 (0.287106s)][7.59969 (0.203916s)][6.51873 (0.202527s)]]
|
|
[[mpfr_float][23.5296 (0.218779s)][8.11058 (0.217624s)][7.16325 (0.222552s)]]
|
|
]
|
|
[table Operator construct(unsigned)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.0603971s)][[*1] (0.0735485s)][[*1] (0.116464s)]]
|
|
[[gmp_float][3.91573 (0.236498s)][2.88171 (0.211945s)][1.81075 (0.210887s)]]
|
|
[[mpfr_float][4.90052 (0.295977s)][4.01118 (0.295017s)][2.62005 (0.305141s)]]
|
|
]
|
|
[table Operator construct(unsigned long long)
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][[*1] (0.0610288s)][[*1] (0.0759005s)][[*1] (0.118511s)]]
|
|
[[gmp_float][8.26247 (0.504249s)][6.69042 (0.507806s)][4.32819 (0.51294s)]]
|
|
[[mpfr_float][10.1593 (0.620013s)][8.45884 (0.64203s)][5.51472 (0.653557s)]]
|
|
]
|
|
[table Operator str
|
|
[[Backend][50 Bits][100 Bits][500 Bits]]
|
|
[[cpp_dec_float][2.95848 (0.0223061s)][3.33461 (0.033471s)][3.0159 (0.132732s)]]
|
|
[[gmp_float][[*1] (0.00753971s)][[*1] (0.0100374s)][[*1] (0.0440106s)]]
|
|
[[mpfr_float][1.25424 (0.00945658s)][1.24943 (0.012541s)][1.09428 (0.0481601s)]]
|
|
]
|
|
|
|
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations
|
|
turned on (/Ox), and used MPIR-2.3.0 and [mpfr]-3.0.0. The tests were run on 32-bit
|
|
Windows Vista machine.
|
|
|
|
[endsect]
|
|
|
|
[section:integer_performance Integer Algorithm Performance]
|
|
|
|
Note that these tests are carefully designed to test performance of the underlying algorithms
|
|
and not memory allocation or variable copying. As usual, performance results should be taken
|
|
with a healthy dose of scepticism, and real-world performance may vary widely depending upon the
|
|
specifics of the program. In each table relative times are given first, with the best performer
|
|
given a score of 1. Total actual times are given in brackets, measured in seconds for 500000
|
|
operations.
|
|
|
|
[table Operator +
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.23704 (0.0274266s)][1.09358 (0.0383278s)][1.26645 (0.0558828s)][1.32188 (0.0916899s)]]
|
|
[[cpp_int(fixed)][1.62044 (0.0359271s)][1.5277 (0.053543s)][1.73059 (0.076363s)][1.71537 (0.118983s)]]
|
|
[[gmp_int][1.87515 (0.0415741s)][1.21699 (0.042653s)][1.15599 (0.0510088s)][[*1] (0.0693631s)]]
|
|
[[tommath_int][[*1] (0.0221711s)][[*1] (0.035048s)][[*1] (0.0441255s)][1.04441 (0.0724435s)]]
|
|
]
|
|
[table Operator +(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0155377s)][[*1] (0.0209523s)][[*1] (0.0306377s)][[*1] (0.043125s)]]
|
|
[[cpp_int(fixed)][1.31904 (0.0204948s)][1.76211 (0.0369203s)][1.52941 (0.0468577s)][1.60412 (0.0691778s)]]
|
|
[[gmp_int][1.96204 (0.0304855s)][2.02569 (0.0424428s)][2.11505 (0.0648002s)][2.65993 (0.114709s)]]
|
|
[[tommath_int][14.0654 (0.218543s)][10.8239 (0.226786s)][7.76691 (0.23796s)][6.10039 (0.263079s)]]
|
|
]
|
|
[table Operator +(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.026624s)][[*1] (0.0291407s)][[*1] (0.0373209s)][[*1] (0.0464919s)]]
|
|
[[cpp_int(fixed)][1.31378 (0.034978s)][1.54897 (0.045138s)][1.53649 (0.0573431s)][1.27833 (0.0594319s)]]
|
|
[[gmp_int][25.5775 (0.680974s)][24.0117 (0.699717s)][19.5633 (0.730121s)][16.8939 (0.785432s)]]
|
|
[[tommath_int][19.4694 (0.518354s)][18.4246 (0.536907s)][14.7715 (0.551288s)][12.3637 (0.574812s)]]
|
|
]
|
|
[table Operator +=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.18405 (0.0196905s)][1.22304 (0.0206476s)][1.25861 (0.0217397s)][1.29525 (0.0220829s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0166298s)][[*1] (0.0168822s)][[*1] (0.0172728s)][[*1] (0.0170492s)]]
|
|
[[gmp_int][39.9082 (0.663668s)][39.4584 (0.666147s)][38.5504 (0.665873s)][39.2231 (0.668722s)]]
|
|
[[tommath_int][30.6219 (0.509238s)][30.4135 (0.513447s)][30.9077 (0.533863s)][32.3086 (0.550835s)]]
|
|
]
|
|
[table Operator -
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.06986 (0.0296064s)][[*1] (0.0381508s)][1.05932 (0.053186s)][1.1766 (0.0844721s)]]
|
|
[[cpp_int(fixed)][1.3304 (0.0368163s)][1.44506 (0.0551303s)][1.4431 (0.0724545s)][1.57255 (0.112898s)]]
|
|
[[gmp_int][1.48072 (0.0409761s)][1.19003 (0.0454007s)][1.0794 (0.0541942s)][[*1] (0.0717934s)]]
|
|
[[tommath_int][[*1] (0.0276731s)][1.10891 (0.0423057s)][[*1] (0.0502076s)][1.08479 (0.0778811s)]]
|
|
]
|
|
[table Operator -(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0147372s)][[*1] (0.0170001s)][[*1] (0.0232882s)][[*1] (0.0310734s)]]
|
|
[[cpp_int(fixed)][1.4267 (0.0210256s)][1.98887 (0.0338109s)][1.83788 (0.0428009s)][1.81269 (0.0563264s)]]
|
|
[[gmp_int][2.07504 (0.0305803s)][2.40928 (0.0409579s)][2.58711 (0.0602493s)][3.26438 (0.101435s)]]
|
|
[[tommath_int][13.5424 (0.199577s)][12.1793 (0.207048s)][9.28855 (0.216314s)][7.49327 (0.232842s)]]
|
|
]
|
|
[table Operator -(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0277377s)][[*1] (0.0296807s)][[*1] (0.0372392s)][[*1] (0.0455855s)]]
|
|
[[cpp_int(fixed)][1.19867 (0.0332484s)][1.48639 (0.0441169s)][1.43253 (0.0533464s)][1.27697 (0.0582111s)]]
|
|
[[gmp_int][24.1794 (0.670683s)][22.9073 (0.679904s)][18.8758 (0.702922s)][16.5837 (0.755975s)]]
|
|
[[tommath_int][18.149 (0.503413s)][17.4116 (0.516787s)][14.0411 (0.52288s)][11.8237 (0.538987s)]]
|
|
]
|
|
[table Operator -=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.26896 (0.0203467s)][1.25722 (0.0206147s)][1.36108 (0.0225485s)][1.18351 (0.0226161s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0160342s)][[*1] (0.0163971s)][[*1] (0.0165667s)][[*1] (0.0191094s)]]
|
|
[[gmp_int][41.1339 (0.659547s)][40.3982 (0.662411s)][39.925 (0.661425s)][34.636 (0.661874s)]]
|
|
[[tommath_int][31.1543 (0.499533s)][31.0303 (0.508806s)][30.7699 (0.509756s)][27.7054 (0.529434s)]]
|
|
]
|
|
[table Operator *
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.11839 (0.0757577s)][1.61061 (0.207951s)][1.4501 (0.696912s)][1.72796 (2.64108s)]]
|
|
[[cpp_int(fixed)][1.01115 (0.0684934s)][1.28687 (0.166152s)][[*1] (0.480595s)][[*1] (1.52844s)]]
|
|
[[gmp_int][[*1] (0.0677384s)][[*1] (0.129113s)][1.09011 (0.523902s)][1.03374 (1.58s)]]
|
|
[[tommath_int][1.6322 (0.110562s)][2.71751 (0.350866s)][2.05222 (0.986288s)][2.0644 (3.15531s)]]
|
|
]
|
|
[table Operator *(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.01611 (0.0229536s)][1.12175 (0.0298152s)][1.16413 (0.0416439s)][1.31747 (0.0666043s)]]
|
|
[[cpp_int(fixed)][1.30215 (0.0294152s)][1.669 (0.0443606s)][1.72395 (0.0616701s)][1.88315 (0.095202s)]]
|
|
[[gmp_int][[*1] (0.0225897s)][[*1] (0.0265791s)][[*1] (0.0357725s)][[*1] (0.0505547s)]]
|
|
[[tommath_int][10.8281 (0.244603s)][10.1516 (0.26982s)][8.76424 (0.313519s)][8.04364 (0.406644s)]]
|
|
]
|
|
[table Operator *(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0570721s)][[*1] (0.0856141s)][[*1] (0.143279s)][[*1] (0.252785s)]]
|
|
[[cpp_int(fixed)][1.10857 (0.0632686s)][1.2951 (0.110878s)][1.20827 (0.173121s)][1.18463 (0.299456s)]]
|
|
[[gmp_int][12.0605 (0.68832s)][8.13434 (0.696415s)][5.21762 (0.747577s)][3.11601 (0.787681s)]]
|
|
[[tommath_int][10.0524 (0.57371s)][7.33116 (0.627651s)][4.85202 (0.695193s)][3.35808 (0.848871s)]]
|
|
]
|
|
[table Operator *=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][111.27 (7.43118s)][67.7078 (7.34138s)][43.3851 (7.4075s)][25.3089 (7.55455s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0667848s)][[*1] (0.108427s)][[*1] (0.170738s)][[*1] (0.298493s)]]
|
|
[[gmp_int][46.3718 (3.09693s)][28.4639 (3.08626s)][18.1719 (3.10264s)][10.5223 (3.14083s)]]
|
|
[[tommath_int][276.674 (18.4776s)][169.146 (18.34s)][108.491 (18.5236s)][63.3261 (18.9024s)]]
|
|
]
|
|
[table Operator /
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][2.68035 (0.595251s)][2.04702 (0.707471s)][1.62314 (0.921536s)][1.43112 (1.38811s)]]
|
|
[[cpp_int(fixed)][[*1] (0.222079s)][[*1] (0.34561s)][[*1] (0.567748s)][[*1] (0.969945s)]]
|
|
[[gmp_int][3.79283 (0.842308s)][2.73668 (0.945824s)][1.86649 (1.05969s)][1.32141 (1.2817s)]]
|
|
[[tommath_int][13.2531 (2.94324s)][11.2054 (3.87271s)][9.83293 (5.58262s)][13.0164 (12.6252s)]]
|
|
]
|
|
[table Operator /(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][4.06026 (0.225473s)][3.45732 (0.340049s)][3.00195 (0.547957s)][2.80587 (0.978029s)]]
|
|
[[cpp_int(fixed)][2.43766 (0.135367s)][2.56264 (0.252052s)][2.44011 (0.445402s)][2.38009 (0.829617s)]]
|
|
[[gmp_int][[*1] (0.0555316s)][[*1] (0.0983563s)][[*1] (0.182534s)][[*1] (0.348566s)]]
|
|
[[tommath_int][35.9988 (1.99907s)][27.1024 (2.66569s)][21.8333 (3.98531s)][25.8066 (8.99528s)]]
|
|
]
|
|
[table Operator /(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.50505 (0.705756s)][1.39347 (1.58556s)][2.63348 (3.57438s)][4.75451 (8.52733s)]]
|
|
[[cpp_int(fixed)][[*1] (0.468925s)][1.12378 (1.27869s)][2.29966 (3.12128s)][4.4844 (8.04288s)]]
|
|
[[gmp_int][2.17234 (1.01866s)][[*1] (1.13785s)][[*1] (1.35728s)][[*1] (1.79352s)]]
|
|
[[tommath_int][4.74612 (2.22557s)][2.70088 (3.07319s)][3.65634 (4.96268s)][6.79408 (12.1853s)]]
|
|
]
|
|
[table Operator /=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.76281 (0.0574966s)][1.76471 (0.0604224s)][1.56085 (0.0716403s)][1.31422 (0.124043s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0326164s)][[*1] (0.0342393s)][[*1] (0.0458981s)][[*1] (0.0943852s)]]
|
|
[[gmp_int][20.2862 (0.661664s)][19.4043 (0.664389s)][14.4881 (0.664976s)][7.14238 (0.674135s)]]
|
|
[[tommath_int][32.9555 (1.07489s)][30.1525 (1.0324s)][22.8324 (1.04796s)][11.7456 (1.10861s)]]
|
|
]
|
|
[table Operator %
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.8501 (0.364131s)][1.46527 (0.476653s)][1.27509 (0.689738s)][1.20064 (1.11769s)]]
|
|
[[cpp_int(fixed)][[*1] (0.196817s)][[*1] (0.325301s)][[*1] (0.540932s)][[*1] (0.930916s)]]
|
|
[[gmp_int][3.2533 (0.640305s)][2.15441 (0.700832s)][1.47898 (0.800029s)][1.07439 (1.00016s)]]
|
|
[[tommath_int][15.3501 (3.02116s)][12.1106 (3.9396s)][11.0689 (5.98752s)][13.5535 (12.6172s)]]
|
|
]
|
|
[table Operator %(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.82761 (0.104331s)][2.01496 (0.202512s)][2.10004 (0.389523s)][2.17252 (0.768097s)]]
|
|
[[cpp_int(fixed)][1.78851 (0.102099s)][1.96844 (0.197838s)][2.02956 (0.376451s)][2.07257 (0.73276s)]]
|
|
[[gmp_int][[*1] (0.057086s)][[*1] (0.100505s)][[*1] (0.185483s)][[*1] (0.353552s)]]
|
|
[[tommath_int][36.3018 (2.07233s)][26.3075 (2.64402s)][21.9525 (4.07183s)][25.6759 (9.07775s)]]
|
|
]
|
|
[table Operator construct
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.40211 (0.0026854s)][[*1] (0.00278639s)][[*1] (0.00322813s)][[*1] (0.0027185s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00191526s)][1.40721 (0.00392103s)][1.90346 (0.00614463s)][2.14621 (0.00583447s)]]
|
|
[[gmp_int][98.705 (0.189046s)][68.9726 (0.192184s)][58.8994 (0.190135s)][70.0525 (0.190438s)]]
|
|
[[tommath_int][105.602 (0.202255s)][74.1994 (0.206748s)][63.6455 (0.205456s)][76.8935 (0.209035s)]]
|
|
]
|
|
[table Operator construct(unsigned)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.73436 (0.00348927s)][[*1] (0.00263476s)][[*1] (0.0027009s)][[*1] (0.00318651s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00201185s)][1.36851 (0.0036057s)][2.07362 (0.00560064s)][1.66856 (0.00531688s)]]
|
|
[[gmp_int][97.2414 (0.195635s)][76.3759 (0.201232s)][72.7396 (0.196462s)][63.8129 (0.20334s)]]
|
|
[[tommath_int][210.112 (0.422713s)][162.652 (0.42855s)][158.33 (0.427634s)][134.626 (0.428987s)]]
|
|
]
|
|
[table Operator construct(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][2.34403 (0.00739542s)][1.66376 (0.00713834s)][1.22989 (0.0074969s)][1.23708 (0.00711417s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00315501s)][[*1] (0.00429049s)][[*1] (0.00609561s)][[*1] (0.0057508s)]]
|
|
[[gmp_int][222.866 (0.703144s)][164.331 (0.705059s)][115.363 (0.70321s)][122.347 (0.703596s)]]
|
|
[[tommath_int][218.681 (0.689941s)][163.796 (0.702765s)][114.57 (0.698376s)][122.422 (0.704027s)]]
|
|
]
|
|
[table Operator gcd
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.16358 (2.74442s)][1.39847 (8.11559s)][1.64677 (22.2518s)][1.95096 (64.4961s)]]
|
|
[[cpp_int(fixed)][[*1] (2.35859s)][1.30986 (7.60133s)][1.67681 (22.6577s)][2.0895 (69.0758s)]]
|
|
[[gmp_int][1.03392 (2.4386s)][[*1] (5.80319s)][[*1] (13.5124s)][[*1] (33.0586s)]]
|
|
[[tommath_int][5.25978 (12.4057s)][4.4619 (25.8932s)][4.15577 (56.1542s)][3.91192 (129.323s)]]
|
|
]
|
|
[table Operator powm
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][2.50722 (2.91621s)][3.5561 (13.406s)][4.37066 (73.483s)][4.88831 (473.91s)]]
|
|
[[cpp_int(fixed)][1.93385 (2.24931s)][3.18107 (11.9922s)][4.20753 (70.7403s)][4.8158 (466.88s)]]
|
|
[[gmp_int][[*1] (1.16313s)][[*1] (3.76986s)][[*1] (16.8128s)][[*1] (96.9476s)]]
|
|
[[tommath_int][1.44081 (1.67584s)][1.8794 (7.08507s)][2.19115 (36.8394s)][2.17186 (210.557s)]]
|
|
]
|
|
[table Operator str
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.17175 (0.00160006s)][1.41999 (0.00329476s)][1.40856 (0.00813784s)][1.52964 (0.0229767s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00136554s)][[*1] (0.00232027s)][[*1] (0.00577741s)][1.14754 (0.0172372s)]]
|
|
[[gmp_int][1.50501 (0.00205515s)][1.52968 (0.00354926s)][1.01989 (0.0058923s)][[*1] (0.015021s)]]
|
|
[[tommath_int][12.2161 (0.0166816s)][16.9577 (0.0393463s)][18.7474 (0.108311s)][22.7368 (0.341528s)]]
|
|
]
|
|
[table Operator |
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0301617s)][[*1] (0.0423404s)][[*1] (0.0522358s)][[*1] (0.0813156s)]]
|
|
[[cpp_int(fixed)][1.0638 (0.0320861s)][1.22566 (0.0518951s)][1.28515 (0.0671305s)][1.16118 (0.094422s)]]
|
|
[[gmp_int][1.76553 (0.0532514s)][1.51489 (0.0641408s)][1.70708 (0.0891706s)][1.77346 (0.14421s)]]
|
|
[[tommath_int][4.37637 (0.131999s)][3.46212 (0.146587s)][2.91875 (0.152463s)][4.19621 (0.341217s)]]
|
|
]
|
|
[table Operator |(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0289129s)][[*1] (0.0351119s)][[*1] (0.0406779s)][[*1] (0.0525891s)]]
|
|
[[cpp_int(fixed)][1.06091 (0.030674s)][1.25979 (0.0442336s)][1.36194 (0.0554009s)][1.37438 (0.0722772s)]]
|
|
[[gmp_int][4.92854 (0.142498s)][4.34687 (0.152627s)][3.71442 (0.151095s)][2.981 (0.156768s)]]
|
|
[[tommath_int][10.9847 (0.317598s)][9.37065 (0.329021s)][8.53651 (0.347248s)][11.2155 (0.589813s)]]
|
|
]
|
|
[table Operator ^
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0305149s)][[*1] (0.04217s)][[*1] (0.0525977s)][[*1] (0.0816632s)]]
|
|
[[cpp_int(fixed)][1.01544 (0.0309861s)][1.24872 (0.0526585s)][1.26661 (0.066621s)][1.15965 (0.0947007s)]]
|
|
[[gmp_int][1.64675 (0.0502505s)][1.47181 (0.0620663s)][1.66038 (0.0873322s)][1.67895 (0.137108s)]]
|
|
[[tommath_int][4.30668 (0.131418s)][3.45859 (0.145849s)][2.91462 (0.153303s)][4.15538 (0.339342s)]]
|
|
]
|
|
[table Operator ^(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.01566 (0.0296088s)][[*1] (0.0356634s)][[*1] (0.0401898s)][[*1] (0.0514097s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0291524s)][1.2393 (0.0441976s)][1.38556 (0.0556856s)][1.38899 (0.0714075s)]]
|
|
[[gmp_int][4.68027 (0.136441s)][4.15243 (0.14809s)][3.74237 (0.150405s)][3.0483 (0.156712s)]]
|
|
[[tommath_int][10.919 (0.318314s)][9.16311 (0.326788s)][8.62554 (0.346659s)][11.6212 (0.597442s)]]
|
|
]
|
|
[table Operator &
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.0346 (0.0303431s)][[*1] (0.0427309s)][[*1] (0.0535587s)][1.06945 (0.0828084s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0293284s)][1.10435 (0.04719s)][1.05262 (0.0563769s)][[*1] (0.0774309s)]]
|
|
[[gmp_int][1.86057 (0.0545675s)][1.58432 (0.0676995s)][1.69164 (0.0906018s)][1.86625 (0.144505s)]]
|
|
[[tommath_int][4.4157 (0.129506s)][3.60396 (0.154s)][2.95985 (0.158525s)][4.4032 (0.340944s)]]
|
|
]
|
|
[table Operator &(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.05874 (0.038946s)][[*1] (0.0483903s)][[*1] (0.063842s)][[*1] (0.100361s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0367853s)][1.05827 (0.0512099s)][1.09114 (0.0696605s)][1.09432 (0.109826s)]]
|
|
[[gmp_int][3.92298 (0.144308s)][2.99447 (0.144903s)][2.228 (0.14224s)][1.42296 (0.142809s)]]
|
|
[[tommath_int][8.79208 (0.323419s)][7.02288 (0.339839s)][5.65271 (0.36088s)][6.27104 (0.629365s)]]
|
|
]
|
|
[table Operator <<
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0248801s)][1.23196 (0.04s)][[*1] (0.0424149s)][[*1] (0.060157s)]]
|
|
[[cpp_int(fixed)][1.08931 (0.027102s)][1.40572 (0.0456418s)][1.3475 (0.0571542s)][1.24573 (0.0749397s)]]
|
|
[[gmp_int][1.05561 (0.0262636s)][[*1] (0.0324686s)][1.09914 (0.0466199s)][1.16315 (0.0699719s)]]
|
|
[[tommath_int][1.60497 (0.0399319s)][2.13048 (0.0691737s)][2.31219 (0.0980712s)][2.74695 (0.165248s)]]
|
|
]
|
|
[table Operator >>
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0213349s)][1.02127 (0.0295019s)][[*1] (0.0327116s)][1.13168 (0.0433804s)]]
|
|
[[cpp_int(fixed)][1.13514 (0.0242181s)][1.16938 (0.0337803s)][1.46999 (0.0480859s)][1.60077 (0.061362s)]]
|
|
[[gmp_int][1.26614 (0.0270129s)][[*1] (0.0288873s)][1.42219 (0.0465221s)][[*1] (0.0383329s)]]
|
|
[[tommath_int][12.0066 (0.25616s)][10.2837 (0.297067s)][9.99696 (0.327017s)][16.0943 (0.616942s)]]
|
|
]
|
|
|
|
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations
|
|
turned on (/Ox), and used MPIR-2.3.0 and [mpfr]-3.0.0. The tests were run on 32-bit
|
|
Windows Vista machine.
|
|
|
|
Linux x86_64 results are broadly similar, except that libtommath performs much better there.
|
|
|
|
[endsect]
|
|
|
|
[section:rational_performance Rational Type Performance]
|
|
|
|
Note that these tests are carefully designed to test performance of the underlying algorithms
|
|
and not memory allocation or variable copying. As usual, performance results should be taken
|
|
with a healthy dose of scepticism, and real-world performance may vary widely depending upon the
|
|
specifics of the program. In each table relative times are given first, with the best performer
|
|
given a score of 1. Total actual times are given in brackets, measured in seconds for 500000
|
|
operations.
|
|
|
|
[table Operator +
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][5.89417 (18.4116s)][6.87256 (47.4698s)][6.65008 (107.715s)][6.53801 (256.244s)]]
|
|
[[mpq_rational][[*1] (3.1237s)][[*1] (6.90715s)][[*1] (16.1975s)][[*1] (39.1929s)]]
|
|
]
|
|
[table Operator +(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][3.62367 (2.46488s)][4.18291 (2.94603s)][4.726 (3.74866s)][6.1388 (5.56817s)]]
|
|
[[mpq_rational][[*1] (0.680215s)][[*1] (0.704303s)][[*1] (0.7932s)][[*1] (0.907046s)]]
|
|
]
|
|
[table Operator +(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.1527 (2.6378s)][1.31751 (3.09863s)][1.58996 (4.00714s)][2.15642 (5.75702s)]]
|
|
[[mpq_rational][[*1] (2.28837s)][[*1] (2.35189s)][[*1] (2.52028s)][[*1] (2.66971s)]]
|
|
]
|
|
[table Operator +=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.18436 (2.7059s)][1.32279 (3.11099s)][1.61398 (4.05389s)][2.20048 (5.84623s)]]
|
|
[[mpq_rational][[*1] (2.2847s)][[*1] (2.35183s)][[*1] (2.51174s)][[*1] (2.6568s)]]
|
|
]
|
|
[table Operator -
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][5.81893 (18.3457s)][6.82209 (47.1928s)][6.64143 (107.498s)][6.51362 (255.137s)]]
|
|
[[mpq_rational][[*1] (3.15277s)][[*1] (6.91765s)][[*1] (16.1859s)][[*1] (39.1698s)]]
|
|
]
|
|
[table Operator -(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][3.72441 (2.48756s)][4.27663 (2.98713s)][4.62109 (3.72114s)][6.17605 (5.56503s)]]
|
|
[[mpq_rational][[*1] (0.667908s)][[*1] (0.698479s)][[*1] (0.805252s)][[*1] (0.901066s)]]
|
|
]
|
|
[table Operator -(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.15627 (2.63239s)][1.32096 (3.12092s)][1.61044 (4.00106s)][2.19378 (5.7644s)]]
|
|
[[mpq_rational][[*1] (2.27663s)][[*1] (2.36262s)][[*1] (2.48445s)][[*1] (2.62761s)]]
|
|
]
|
|
[table Operator -=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.1984 (2.73444s)][1.34141 (3.15698s)][1.64159 (4.06997s)][2.23017 (5.88108s)]]
|
|
[[mpq_rational][[*1] (2.28174s)][[*1] (2.35348s)][[*1] (2.47929s)][[*1] (2.63706s)]]
|
|
]
|
|
[table Operator *
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][5.4306 (32.5882s)][6.91805 (89.9436s)][6.94556 (207.307s)][6.88704 (492.151s)]]
|
|
[[mpq_rational][[*1] (6.00084s)][[*1] (13.0013s)][[*1] (29.8475s)][[*1] (71.4604s)]]
|
|
]
|
|
[table Operator *(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][2.12892 (2.51376s)][2.47245 (3.07841s)][2.86832 (3.93619s)][3.94086 (6.02565s)]]
|
|
[[mpq_rational][[*1] (1.18077s)][[*1] (1.24508s)][[*1] (1.3723s)][[*1] (1.52902s)]]
|
|
]
|
|
[table Operator *(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.32254 (5.43565s)][1.56078 (6.73163s)][1.97701 (9.32522s)][2.85404 (15.1573s)]]
|
|
[[mpq_rational][[*1] (4.11002s)][[*1] (4.313s)][[*1] (4.71682s)][[*1] (5.31082s)]]
|
|
]
|
|
[table Operator *=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][6.29806 (58.1188s)][6.30556 (59.5076s)][6.3385 (62.1007s)][6.55345 (67.6905s)]]
|
|
[[mpq_rational][[*1] (9.22804s)][[*1] (9.43733s)][[*1] (9.79739s)][[*1] (10.329s)]]
|
|
]
|
|
[table Operator /
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][4.4269 (66.8031s)][6.40103 (173.527s)][6.32347 (348.193s)][6.61148 (824.063s)]]
|
|
[[mpq_rational][[*1] (15.0903s)][[*1] (27.1093s)][[*1] (55.0637s)][[*1] (124.641s)]]
|
|
]
|
|
[table Operator /(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.78772 (2.50984s)][2.10623 (3.10606s)][2.46986 (3.99358s)][3.37428 (5.96678s)]]
|
|
[[mpq_rational][[*1] (1.40393s)][[*1] (1.4747s)][[*1] (1.61693s)][[*1] (1.76831s)]]
|
|
]
|
|
[table Operator /(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][1.29695 (5.45454s)][1.55248 (6.85353s)][1.93237 (9.28765s)][2.75211 (14.8541s)]]
|
|
[[mpq_rational][[*1] (4.20568s)][[*1] (4.41458s)][[*1] (4.80635s)][[*1] (5.39734s)]]
|
|
]
|
|
[table Operator /=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][6.19401 (58.4278s)][6.20135 (59.643s)][6.21327 (62.0338s)][6.40576 (67.6778s)]]
|
|
[[mpq_rational][[*1] (9.43295s)][[*1] (9.61774s)][[*1] (9.98407s)][[*1] (10.5652s)]]
|
|
]
|
|
[table Operator construct
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][[*1] (0.00978288s)][[*1] (0.0100574s)][[*1] (0.0101393s)][[*1] (0.0101847s)]]
|
|
[[mpq_rational][39.1516 (0.383015s)][38.3523 (0.385725s)][37.5812 (0.381048s)][37.6007 (0.382953s)]]
|
|
]
|
|
[table Operator construct(unsigned)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][[*1] (0.0548151s)][[*1] (0.0557542s)][[*1] (0.055825s)][[*1] (0.0552808s)]]
|
|
[[mpq_rational][7.21073 (0.395257s)][7.1016 (0.395944s)][7.02046 (0.391917s)][7.16881 (0.396297s)]]
|
|
]
|
|
[table Operator construct(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][[*1] (0.0605156s)][[*1] (0.0616657s)][[*1] (0.0592056s)][[*1] (0.0603081s)]]
|
|
[[mpq_rational][35.1604 (2.12775s)][34.7575 (2.14335s)][35.7232 (2.11502s)][35.0437 (2.11342s)]]
|
|
]
|
|
[table Operator str
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_rational][5.48898 (0.0208949s)][8.49668 (0.0546688s)][10.107 (0.121897s)][10.5339 (0.310584s)]]
|
|
[[mpq_rational][[*1] (0.0038067s)][[*1] (0.00643413s)][[*1] (0.0120606s)][[*1] (0.0294843s)]]
|
|
]
|
|
|
|
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations
|
|
turned on (/Ox), and used MPIR-2.3.0 and [mpfr]-3.0.0. The tests were run on 32-bit
|
|
Windows Vista machine.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:map Roadmap]
|
|
|
|
* Support for atomic loads and stores is not currently supported, but will become more important as a larger number of floating point algorithms become parallelized.
|
|
|
|
[section:hist History]
|
|
|
|
[h4 Multiprecision-3.2.3 (Boost-1.72)]
|
|
|
|
* Big `constexpr` update allows __cpp_int and __float128 arithmetic to be fully `constexpr` with gcc and clang 9 or later,
|
|
or any compiler supporting `std::is_constant_evaluated()`.
|
|
|
|
[h4 Multiprecision-3.1.3 (Boost-1.71)]
|
|
|
|
* Support hexfloat io-formatting for float128.
|
|
* Fix various bugs in variable precision interconversions.
|
|
* Respect uppercase for '0x' prefix outputs.
|
|
* Incorporate some unit tests from the Etherium project.
|
|
* Fix some gcc warnings.
|
|
|
|
[h4 Multiprecision-3.1.2 (Boost-1.70)]
|
|
|
|
* Fix various conversion issues in the traits classes, check for compatibility with Boost.Optional.
|
|
* Prevent instantiation of `std::numeric_limits` on any old type when checking for convertibility. See [@https://github.com/boostorg/multiprecision/issues/98 #98].
|
|
* Update variable precision code to accound for arbitrary precision integers. See [@https://github.com/boostorg/multiprecision/issues/103 #103].
|
|
* Add support for XML serialization archives.
|
|
* Fix bug in fixed precision iostream formatting in `mpf_float` and `mpfr_float`. See [@https://github.com/boostorg/multiprecision/issues/113 #113].
|
|
* Add more overloads for special functions which are better handled natively by MPFR.
|
|
* Fixed bug in generic `exp` implementation which could cause invariant failure.
|
|
* Fixed generic conversion from float to integer to avoid undefined behaviour. See [@https://github.com/boostorg/multiprecision/issues/110 #110].
|
|
|
|
[h4 Multiprecision-3.1.1 (Boost-1.69)]
|
|
|
|
* Big update to better support variable precision types so that the precision of the result
|
|
is always the largest of all the arguments.
|
|
* Add support for allocators that are `final` in __cpp_int.
|
|
* Removed use of deprecated Boost.Endian in favour of Predef.
|
|
* Add support for `std::string_view`.
|
|
* Fixed minor bug in constant initialization. See [@https://github.com/boostorg/multiprecision/issues/67 #67].
|
|
* Make assignment of non-finite value to `cpp_int` a runtime errors. See [@https://github.com/boostorg/multiprecision/issues/58 #58].
|
|
* Added typedefs for `cpp_bin_float_oct` and `cpp_complex_oct`.
|
|
|
|
[h4 Multiprecision-3.1.0 (Boost-1.68)]
|
|
|
|
* Support added for complex multiprecision numbers.
|
|
* Changed conversion to unsigned integer types to be truncating to match standard defined behaviour.
|
|
* Correct bug in MPFR string formatting.
|
|
* Fix undefined behaviour in cpp_dec_float conversion from long long.
|
|
* Add support for Eigen interoperability.
|
|
* float128.hpp: Fix Intel on Windows build.
|
|
* Fix type used in temporaries when expanding expression templates containing mixed expressions.
|
|
* Fix infinite loop in gmp_float to fixed-point string conversion.
|
|
* Update the expression templates to issue static_asserts with better error messages when you try and do something unsupported.
|
|
* Fix bug in cpp_int where incrementing to zero doesn't set the sign correctly.
|
|
* Remove erroneous use of std::move, and rely on NVRO instead.
|
|
* Fix up support for changes to MPIR-3.0.
|
|
* Fix various conversion errors in cpp_bin_float when the exponent type is a `long long`, or else we're converting to
|
|
an integer that is wider than we are.
|
|
* Fix compatibility issue with GCC-8 caused by the introduction of `std::byte`.
|
|
|
|
[h4 Multiprecision-3.0.0 (Boost-1.67)]
|
|
|
|
* [*Breaking Change:] When converting a multiprecision integer to a narrower type, if the value is too large (or negative) to
|
|
fit in the smaller type, then the result is either the maximum (or minimum) value of the target type. This was always the intended
|
|
behaviour, but was somewhat haphazardly enforced before. If you really do want just the low order N bits of a value, then you will
|
|
need to mask these out prior to the case, for example: `static_cast<unsigned>(~static_cast<unsigned>(0) & my_value)`. Note that
|
|
technically (to avoid undefined behaviour) you should do the same thing with built in integer types too.
|
|
See [@https://svn.boost.org/trac/boost/ticket/13109 #13109].
|
|
* Fix bug in conversion of decimal to rational types (zero needs special handling), see [@https://svn.boost.org/trac/boost/ticket/13148 #13148].
|
|
* Fix conversion from cpp_bin_float to a wider built in integer type, see [@https://svn.boost.org/trac/boost/ticket/13301 #13301].
|
|
* Improve performance heurists used in cpp_bin_float exp function.
|
|
* Fix bug in floor/ceil and cpp_bin_float when the exponent type is wider than an int, see [@https://svn.boost.org/trac/boost/ticket/13264 #13264].
|
|
* Disable explicit conversion operator when the target type is already constructible from this type, see [@https://github.com/boostorg/multiprecision/issues/30 #30].
|
|
* Fix support for changes new to MPIR-3.0, see [@https://svn.boost.org/trac/boost/ticket/13124 #13124].
|
|
|
|
[h4 Multiprecision-2.3.2 (Boost-1.65)]
|
|
|
|
* Updated expression templates to store arithmetic literals directly in the expression template to prevent dangling references, see [@https://github.com/boostorg/multiprecision/issues/19 #19].
|
|
* Fix various issues with huge values and overflow in the trig, pow and exp functions, see [@https://github.com/boostorg/multiprecision/issues/24 #24].
|
|
* Fix error handling of checked cpp_int multiply that could cause some overflows to be missed.
|
|
|
|
[h4 Multiprecision-2.3.1 (Boost-1.64)]
|
|
|
|
* In `cpp_bin_float` prevent double rounding when converting to a denormalized float. See [@https://svn.boost.org/trac/boost/ticket/12527 #12527].
|
|
* Fix bug in integer sqrt for very small integers. See [@https://svn.boost.org/trac/boost/ticket/12559 #12559].
|
|
* Fix conversion to signed-zero in `cpp_bin_float`.
|
|
* Change `cpp_bin_float` rounding code to round at arbitrary location so we can use it for conversions, see [@https://svn.boost.org/trac/boost/ticket/12527 #12527].
|
|
* Improve performance of 128-bit bit-scan operations.
|
|
* Fix subtraction of very small quantities in `cpp_bin_float`. See: [@https://svn.boost.org/trac/boost/ticket/12580 #12580].
|
|
* Bring error handling into line with C99 Annex F. See [@https://svn.boost.org/trac/boost/ticket/12581 #12581].
|
|
* Fix bitwise export of trivial `cpp_int`'s, see [@https://svn.boost.org/trac/boost/ticket/12627 #12627].
|
|
* Fix `ilogb` (and code that uses it) to consistently return the smallest value of the exponent type when the argument is zero, see [@https://svn.boost.org/trac/boost/ticket/12625 #12625].
|
|
* Allow conversion from `__float128` to `cpp_bin_float`.
|
|
* Fix bug in left shift of `cpp_int` which would result in bit-loss, see [@https://svn.boost.org/trac/boost/ticket/12790 #12790].
|
|
* Fixed bugs in bounded but variable precision `cpp_int`'s caused by over-aggressive constexpr optimization, see [@https://svn.boost.org/trac/boost/ticket/12798 #12798].
|
|
|
|
|
|
[h4 Multiprecision-2.3.0 (Boost-1.63)]
|
|
|
|
* Added support for all the C99 math functions.
|
|
* Extended generic-interconversions to handle narrowing cases as well, changed convert_to member function and hence explicit
|
|
conversion operators to use the same conversion code as the explicit constructors.
|
|
* Fix IO stream parsing error, see [@https://svn.boost.org/trac/boost/ticket/12488 #12488].
|
|
* Make default constructed floating point types all zero for consistency, see [@https://svn.boost.org/trac/boost/ticket/12500 #12500].
|
|
* Fix conversion of cpp_bin_float to float/double/long double when the exponent value would overflow an int, see [@https://svn.boost.org/trac/boost/ticket/12512 #12512].
|
|
* Fix cpp_bin_float subtractions that yield signed-zeros, see [@https://svn.boost.org/trac/boost/ticket/12524 #12524].
|
|
* Fix ceil/trunc/round applied to cpp_bin_float and yielding a signed zero, see [@https://svn.boost.org/trac/boost/ticket/12525 #12525].
|
|
|
|
[h4 Multiprecision-2.2.8 (Boost-1.62)]
|
|
|
|
* Added support for hashing via `Boost.Hash` or `std::hash`.
|
|
* Fixed some arithmetic operations in cpp_bin_float and cpp_dec_float that should generate a NaN, see [@https://svn.boost.org/trac/boost/ticket/12157 #12157].
|
|
* Prevent inadvertant instantiation of variable-precision `mpfr_float_backend` with fixed allocation.
|
|
* Fixed division over/underflow in cpp_bin_float, see [@https://svn.boost.org/trac/boost/ticket/12167 #12167].
|
|
* Added support for signed-zeros throughout the library, including support for `signbit` and `copysign`, mpfr, float128, and cpp_bin_float types
|
|
should now respect signed-zeros correctly.
|
|
* Fixed bug in conversion of cpp_bin_float infinities to double etc, see [@https://svn.boost.org/trac/boost/ticket/12196 #12196].
|
|
* Fix add and subtract of cpp_bin_float when the exponents would overflow., see [@https://svn.boost.org/trac/boost/ticket/12198 #12198].
|
|
* Improve variable-precision support in mpfr and mpf backends, allow these types to be used with Boost.Math.
|
|
* Fixed bug in subtraction of signed infinities in cpp_bin_float, see [@https://svn.boost.org/trac/boost/ticket/12209 #12209].
|
|
* Fix result of sqrt(infinity) in cpp_bin_float (result should be infinity), see [@https://svn.boost.org/trac/boost/ticket/12227 #12227].
|
|
* Added workaround in gmp.hpp for recent MPIR releases which are not quite source-compatible with GMP on Windows x64.
|
|
* Allow `cpp_int` code to be used with /RTCc with MSVC.
|
|
* Fix conversion of `cpp_int` to signed integer when the result is INT_MIN, see [@https://svn.boost.org/trac/boost/ticket/12343 #12343].
|
|
* Update uBlas support to match latest uBlas code.
|
|
* Fix some errors present when building on big-endian machines (not all `cpp_int` constructors are available on non-little-endian machines).
|
|
* Fix fencepost error in rational to float conversion routines, see [@https://svn.boost.org/trac/boost/ticket/12327 #12327].
|
|
* Fix some Oracle C++ compiler compatibility issues.
|
|
* Add modf support to complete C90 compatibility.
|
|
* Fix self assignment bug in expression template code for expressions such as `a = a * a * a`, see [@https://svn.boost.org/trac/boost/ticket/12408 #12408].
|
|
* Fixed some compiler errors that occur when converting from `cpp_int` to `cpp_bin_float`.
|
|
|
|
[h4 Multiprecision-2.2.7 (Boost-1.61)]
|
|
|
|
* Fixed bug in stream input for integer types, see [@https://svn.boost.org/trac/boost/ticket/11857 #11857].
|
|
* Fixed some ambiguous conversions involving expression templates see [@https://svn.boost.org/trac/boost/ticket/11922 #11922].
|
|
* Add expression template aware min/max overloads see [@https://svn.boost.org/trac/boost/ticket/11149 #11149].
|
|
* Fix bug in right shifting negative small integers in cpp_int see [@https://svn.boost.org/trac/boost/ticket/11999 #11999].
|
|
* Use memmove for bitshifts in cpp_int when possible see [@https://svn.boost.org/trac/boost/ticket/9233 #9233].
|
|
* Use memcpy for data import into cpp_int where possible, see [@https://svn.boost.org/trac/boost/ticket/9235 #9235].
|
|
* Changed `cpp_bin_float.convert_to<double>()` to a function template rather than proceding via `long double` to avoid
|
|
double-rounding bug, see [@https://svn.boost.org/trac/boost/ticket/12039 #12039].
|
|
* Fixed conversions from NaN's and Infinities, see [@https://svn.boost.org/trac/boost/ticket/12112 #12112].
|
|
* Enabled better support for Clang on Windows.
|
|
* Fixed handling of NaN's and Infinities in basic arithmetic for cpp_dec_float and cpp_bin_float, see [@https://svn.boost.org/trac/boost/ticket/12090 #12090].
|
|
* Fixed fencepost error in cpp_bin_float subtraction.
|
|
* Fixed double-rounding in conversion to float routines for cpp_bin_float, see [@https://svn.boost.org/trac/boost/ticket/12039 #12039].
|
|
* Make float128 denorm aware, see [@https://svn.boost.org/trac/boost/ticket/12075 #12075].
|
|
* Allow the library and tests to be used without exception handling support, see [@https://svn.boost.org/trac/boost/ticket/12070 #12070].
|
|
* Fixed buggy comparison operator overloads for boost::rational.
|
|
* Added some workarounds for Oracle C++.
|
|
* Fixed some missing typecasts for cases where cpp_int's limb_type is wider than unsigned.
|
|
|
|
|
|
[h4 Multiprecision-2.2.6 (Boost-1.60)]
|
|
|
|
* Fixed result of Miller Rabin primality test for value 2, see [@https://svn.boost.org/trac/boost/ticket/11495 #11495].
|
|
* Improved initialization of cpp_int from very large strings of hex or octal digits, see [@https://svn.boost.org/trac/boost/ticket/11590 #11590].
|
|
* Fixed fmod behaviour for negative divisors, see [@https://svn.boost.org/trac/boost/ticket/11641 #11641].
|
|
* Fixed infinite division loop in cpp_int special case, see [@https://svn.boost.org/trac/boost/ticket/11648 #11648].
|
|
* Patched missing return statement in [@https://svn.boost.org/trac/boost/ticket/11762 #11762].
|
|
* Fixed mixed mode arithmetic compiler error in [@https://svn.boost.org/trac/boost/ticket/11764 #11764].
|
|
* Fixed over-aggressive use of noexcept in [@https://svn.boost.org/trac/boost/ticket/11826 #11826].
|
|
|
|
|
|
[h4 Multiprecision-2.2.5 (Boost-1.59)]
|
|
|
|
* Depricated boost/multiprecision/random.hpp as it's no longer needed, updated random examples to match.
|
|
* Fixed a bug in cpp_int's right shift operator when shifting negative values - semantics now gives the
|
|
same values as shifting 2's compliment integers, though not the same bit pattern.
|
|
* Fixed support for GCC-4.6.4 in C++0x mode by disabling conditional noexcept suppoprt for that compiler
|
|
see [@https://svn.boost.org/trac/boost/ticket/11402 #11402].
|
|
* Suppressed numerous compiler warnings.
|
|
|
|
[h4 Multiprecision-2.2.4 (Boost-1.58)]
|
|
|
|
* Changed `frexp` to always be non-expression template generating, see: [@https://svn.boost.org/trac/boost/ticket/10993 10993].
|
|
* Improved support of cpp_dec_float on Cygwin and other platforms with missing long double support, see [@https://svn.boost.org/trac/boost/ticket/10924 10924].
|
|
* Improved noexcept support and added some more tests, see [@https://svn.boost.org/trac/boost/ticket/10990 10990].
|
|
* Various workarounds applied for Intel-15.0 and Solaris-12.4 compilers.
|
|
|
|
[h4 Multiprecision-2.2.3 (Boost-1.57)]
|
|
|
|
* Changed rational to float conversions to exactly round to nearest, see [@https://svn.boost.org/trac/boost/ticket/10085 10085].
|
|
* Added improved generic float to rational conversions.
|
|
* Fixed rare bug in exponent function for __cpp_bin_float.
|
|
* Fixed various minor documentation issues.
|
|
|
|
[h4 Multiprecision-2.2.2 (Boost-1.56)]
|
|
|
|
* Change floating-point to rational conversions to be implicit, see [@https://svn.boost.org/trac/boost/ticket/10082 10082].
|
|
* Fix definition of checked_cpp_rational typedef.
|
|
|
|
[h4 Multiprecision-2.2.1]
|
|
|
|
* Fix bug in assignment from string in cpp_int, see [@https://svn.boost.org/trac/boost/ticket/9936 9936].
|
|
|
|
[h4 Multiprecision-2.2.0]
|
|
|
|
* Moved to Boost.Multiprecision specific version number - we have one breaking change in Boost-1.54
|
|
which makes this major version 2, plus two releases with new features since then.
|
|
* Added new __cpp_bin_float backend for binary floating-point.
|
|
* Added MSVC-specific #include for compiler intrinsics, see [@https://svn.boost.org/trac/boost/ticket/9336 9336].
|
|
* Fixed various typos in docs, see [@https://svn.boost.org/trac/boost/ticket/9432 9432].
|
|
* Fixed __gmp_rational to allow move-copy from an already copied-from object, see [@https://svn.boost.org/trac/boost/ticket/9497 9497].
|
|
* Added list of values for numeric_limits.
|
|
|
|
[h4 Boost-1.55]
|
|
|
|
* Added support for Boost.Serialization.
|
|
* Suppressed some GCC warnings. See [@https://svn.boost.org/trac/boost/ticket/8872 8872].
|
|
* Fixed bug in pow for large integer arguments. See [@https://svn.boost.org/trac/boost/ticket/8809 8809].
|
|
* Fixed bug in pow for calculation of 0[super N]. See [@https://svn.boost.org/trac/boost/ticket/8798 8798].
|
|
* Fixed bug in fixed precision cpp_int IO code that causes conversion to string to fail when the
|
|
bit count is very small (less than CHAR_BIT). See [@https://svn.boost.org/trac/boost/ticket/8745 8745].
|
|
* Fixed bug in cpp_int that causes left shift to fail when a fixed precision type would overflow.
|
|
See [@https://svn.boost.org/trac/boost/ticket/8741 8741].
|
|
* Fixed some cosmetic warnings from cpp_int. See [@https://svn.boost.org/trac/boost/ticket/8748 8748].
|
|
* Fixed calls to functions which are required to be macros in C99. See [@https://svn.boost.org/trac/boost/ticket/8732 8732].
|
|
* Fixed bug that causes construction from INT_MIN, LONG_MIN etc to fail in cpp_int. See [@https://svn.boost.org/trac/boost/ticket/8711 8711].
|
|
|
|
[h4 1.54]
|
|
|
|
* [*Breaking change] renamed `rational_adapter` to `rational_adaptor`.
|
|
* Add support for [mpfi].
|
|
* Add logged_adaptor.
|
|
* Add support for 128-bit floats via GCC's `__float128` or Intel's `_Quad` data types.
|
|
* Add support for user-defined literals in cpp_int, improve `constexpr` support.
|
|
* Fixed bug in integer division of `cpp_int` that results in incorrect sign of `cpp_int` when both arguments are small enough
|
|
to fit in a `double_limb_type`. See [@https://svn.boost.org/trac/boost/ticket/8126 8126].
|
|
* Fixed bug in subtraction of a single limb in `cpp_int` that results in incorrect value when the result should have a 0
|
|
in the last limb: [@https://svn.boost.org/trac/boost/ticket/8133 8133].
|
|
* Fixed bug in `cpp_int` where division of 0 by something doesn't get zero in the result: [@https://svn.boost.org/trac/boost/ticket/8160 8160].
|
|
* Fixed bug in some transcendental functions that caused incorrect return values when variables are reused, for example with
|
|
`a = pow(a, b)`. See [@https://svn.boost.org/trac/boost/ticket/8326 8326].
|
|
* Fixed some assignment operations in the mpfr and gmp backends to be safe if the target has been moved from: [@https://svn.boost.org/trac/boost/ticket/8326 8667].
|
|
* Fixed bug in `cpp_int` that gives incorrect answer for 0%N for large N: [@https://svn.boost.org/trac/boost/ticket/8670 8670].
|
|
* Fixed set_precision in mpfr backend so it doesn't trample over an existing value: [@https://svn.boost.org/trac/boost/ticket/8692 8692].
|
|
|
|
[h4 1.53]
|
|
|
|
* First Release.
|
|
* Fix bug in [@https://svn.boost.org/trac/boost/ticket/7878 cpp_int division].
|
|
* Fix issue [@https://svn.boost.org/trac/boost/ticket/7806 #7806].
|
|
|
|
[h4 Post review changes]
|
|
|
|
* Non-expression template operators further optimised with rvalue reference support.
|
|
* Many functions made `constexp`.
|
|
* Differentiate between explicit and implicit conversions in the number constructor.
|
|
* Removed "mp_" prefix from types.
|
|
* Allowed mixed precision arithmetic.
|
|
* Changed ExpressionTemplates parameter to class `number` to use enumerated values rather than true/false.
|
|
* Changed ExpressionTemplate parameter default value to use a traits class so that the default value depends on the backend used.
|
|
* Added support for fused-multiply-add/subtract with GMP support.
|
|
* Tweaked expression template unpacking to use fewer temporaries when the LHS also appears in the RHS.
|
|
* Refactored `cpp_int_backend` based on review comments with new template parameter structure.
|
|
* Added additional template parameter to `mpfr_float_backend` to allow stack-based allocation.
|
|
* Added section on mixed precision arithmetic, and added support for operations yielding a higher precision result
|
|
than either of the arguments.
|
|
* Added overloads of integer-specific functions for built in integer types.
|
|
|
|
[h4 Pre-review history]
|
|
|
|
*2011-2012, John Maddock adds an expression template enabled front end to Christopher's code,
|
|
and adds support for other backends.
|
|
* 2011, Christopher Kormanyos publishes the decimal floating-point code under the Boost
|
|
Software Licence. The code is published as: [@http://doi.acm.org/10.1145/1916461.1916469
|
|
"Algorithm 910: A Portable C++ Multiple-Precision
|
|
System for Special-Function Calculations"], in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM,
|
|
2011.
|
|
* 2002-2011, Christopher Kormanyos develops the all C++ decimal arithmetic floating-point
|
|
code.
|
|
|
|
[endsect]
|
|
|
|
[section:todo TODO]
|
|
|
|
|
|
|
|
More a list of what ['could] be done, rather than what ['should] be done (which may be a much smaller list!).
|
|
|
|
* Add back-end support for libdecNumber.
|
|
* Add an adaptor back-end for complex number types.
|
|
* Add better multiplication routines (Karatsuba, FFT etc) to cpp_int_backend.
|
|
* Add assembly level routines to cpp_int_backend.
|
|
* Can ring types (exact floating-point types) be supported? The answer should be yes, but someone needs to write it,
|
|
the hard part is IO and binary-decimal conversion.
|
|
* Should there be a choice of rounding mode (probably MPFR specific)?
|
|
* We can reuse temporaries in multiple subtrees (temporary caching).
|
|
* cpp_dec_float should round to nearest.
|
|
* A 2's complement fixed precision int that uses exactly N bits and no more.
|
|
|
|
Things requested in review:
|
|
|
|
* The performances of mp_number<a_trivial_adaptor<float>, false>respect to
|
|
float and mp_number<a_trivial_adaptor<int>, false> and int should be
|
|
given to show the cost of using the generic interface (Mostly done, just need to update docs to the latest results).
|
|
* Should we provide min/max overloads for expression templates? (Not done - we can't overload functions declared in the std namespace :-( ).
|
|
* The rounding applied when converting must be documented (Done).
|
|
* Document why we don't abstract out addition/multiplication algorithms etc. (done - FAQ)
|
|
* Document why we don't use proto (compile times) (Done).
|
|
* We can reuse temporaries in multiple subtrees (temporary caching) Moved to TODO list.
|
|
* Emphasise in the docs that ET's may reorder operations (done 2012/10/31).
|
|
* Document what happens to small fixed precision cpp_int's (done 2012/10/31).
|
|
* The use of bool in template parameters could be improved by the use of
|
|
an enum class which will be more explicit. E.g `enum class expression_template {disabled, enabled};
|
|
enum class sign {unsigned, signed};` (Partly done 2012/09/15, done 2012/10/31).
|
|
* Each back-end should document the requirements it satisfies (not currently scheduled for inclusion: it's
|
|
deliberately an implementation detail, and "optional" requirements are optimisations which can't be detected
|
|
by the user). Not done: this is an implementation detail, the exact list of requirements satisfied is purely
|
|
an optimization, not something the user can detect.
|
|
* A backend for an overflow aware integers (done 2012/10/31).
|
|
* IIUC convert_to is used to emulate in c++98 compilers C++11 explicit
|
|
conversions. Could the explicit conversion operator be added on
|
|
compilers supporting it? (Done 2012/09/15).
|
|
* The front-end should make the differences between implicit and explicit
|
|
construction (Done 2012/09/15).
|
|
* The tutorial should add more examples concerning implicit or explicit
|
|
conversions. (Done 2012/09/15).
|
|
* The documentation must explain how move semantics helps in this domain
|
|
and what the backend needs to do to profit from this optimization. (Done 2012/09/15).
|
|
* The documentation should contain Throws specification on the mp_number
|
|
and backend requirements operations. (Done 2012/09/15).
|
|
* The library interface should use the noexcept (BOOST_NOEXCEPT, ...)
|
|
facilities (Done 2012/09/15).
|
|
* It is unfortunate that the generic mp_number front end can not make use
|
|
constexpr as not all the backends can ensure this (done - we can go quite a way).
|
|
* literals: The library doesn't provide some kind of literals. I think that the
|
|
mp_number class should provide a way to create literals if the backend
|
|
is able to. (Done 2012/09/15).
|
|
* The ExpresionTemplate parameter could be defaulted to a traits class for more sensible defaults (done 2012/09/20).
|
|
* In a = exp1 op exp2 where a occurs inside one of exp1 or exp2 then we can optimise and eliminate one more temporary (done 2012/09/20).
|
|
|
|
|
|
|
|
[h4 Pre-Review Comments]
|
|
|
|
* Make fixed precision orthogonal to Allocator type in cpp_int. Possible solution - add an additional MaxBits
|
|
template argument that defaults to 0 (meaning keep going till no more space/memory). Done.
|
|
* Can ring types (exact floating-point types) be supported? The answer should be yes, but someone needs to write it (Moved to TODO list).
|
|
* Should there be a choice of rounding mode (probably MPFR specific)? Moved to TODO list.
|
|
* Make the exponent type for cpp_dec_float a template parameter, maybe include support for big-integer exponents.
|
|
Open question - what should be the default - int32_t or int64_t? (done 2012/09/06)
|
|
* Document the size requirements of fixed precision ints (done 2012/09/15).
|
|
* Document std lib function accuracy (done 2012/09/15).
|
|
* Be a bit clearer on the effects of sign-magnitude representation of cpp_int - min == -max etc - done.
|
|
* Document cpp_dec_float precision, rounding, and exponent size (done 2012/09/06).
|
|
* Can we be clearer in the docs that mixed arithmetic doesn't work (no longer applicable as of 2012/09/06)?
|
|
* Document round functions behaviour better (they behave as in C++11) (added note 2012/09/06).
|
|
* Document limits on size of cpp_dec_float (done 2012/09/06).
|
|
* Add support for fused multiply add (and subtract). GMP mpz_t could use this (done 2012/09/20).
|
|
|
|
[endsect]
|
|
|
|
[section:faq FAQ]
|
|
|
|
[variablelist
|
|
[[Why do I get compiler errors when passing a `number` to a template function?]
|
|
[Most likely you are actually passing an expression template type to the function and
|
|
template-argument-deduction deduces the "wrong" type. Try casting the arguments
|
|
involving expressions to the actual number type, or as a last resort turning off
|
|
expression template support in the number type you are using.]]
|
|
[[When is expression template support a performance gain?]
|
|
[As a general rule, expression template support adds a small runtime overhead
|
|
creating and unpacking the expression templates, but greatly reduces the number of
|
|
temporaries created. So it's most effective in improving performance when the cost
|
|
of creating a temporary is high: for example when creating a temporary involves a memory
|
|
allocation. It is least effective (and may even be a dis-optimisation) when temporaries
|
|
are cheap: for example if the number type is basically a thin wrapper around a native
|
|
arithmetic type. In addition, since the library makes extensive use of thin inline wrapper
|
|
functions, turning on compiler optimization is essential to achieving high performance.]]
|
|
[[Do expression templates reorder operations?]
|
|
[Yes they do, sometimes quite radically so, if this is a concern then they should be turned
|
|
off for the number type you are using.]]
|
|
[[I can't construct my number type from ['some other type], but the docs indicate that the conversion should be allowed, what's up?]
|
|
[Some conversions are ['explicit], that includes construction from a string, or constructing from any type
|
|
that may result in loss of precision (for example constructing an integer type from a float).]]
|
|
[[Why do I get an exception thrown (or the program crash due to an uncaught exception) when using the bitwise operators on a checked `cpp_int`?]
|
|
[Bitwise operations on negative values (or indeed any signed integer type) are unspecified by the standard. As a result
|
|
any attempt to carry out a bitwise operation on a negative checked-integer will result in a `std::range_error` being thrown.]]
|
|
[[Why do I get compiler errors when trying to use the complement operator?]
|
|
[Use of the complement operator on signed types is problematic as the result is unspecified by the standard, and is further
|
|
complicated by the fact that most extended precision integer types use a sign-magnitude representation rather than the 2's
|
|
complement one favored by most native integer types. As a result the complement operator is deliberately disabled for
|
|
checked `cpp_int`'s. Unchecked `cpp_int`'s give the same valued result as a 2's complement type would, but not the same bit-pattern.]]
|
|
[[Why can't I negate an unsigned type?]
|
|
[The unary negation operator is deliberately disabled for unsigned integer types as its use would almost always be a programming error.]]
|
|
[[Why doesn't the library use proto?]
|
|
[A very early version of the library did use proto, but compile times became too slow
|
|
for the library to be usable. Since the library only required a tiny fraction of what
|
|
proto has to offer anyway, a lightweight expression template mechanism was used instead.
|
|
Compile times are still too slow...]]
|
|
[[Why not abstract out addition/multiplication algorithms?]
|
|
[This was deemed not to be practical: these algorithms are intimately
|
|
tied to the actual data representation used.]]
|
|
[[How do I choose between Boost.Multiprecision `cpp_bin_50` and `cpp_dec_50`?]
|
|
[Unless you have a specific reason to choose `cpp_dec_`, then the default choice should be `cpp_bin_`,
|
|
for example using the convenience `typedefs` like `boost::multiprecision::cpp_bin_50` or `boost::multiprecision::cpp_bin_100`.
|
|
|
|
In general, both work well and give the same results and at roughly the same speed with `cpp_dec_50` sometimes faster.
|
|
|
|
`cpp_dec_` was developed first paving the way for `cpp_bin_`.
|
|
`cpp_dec_` has several guard digits and is not rounded at all, using 'brute force' to get the promised number of decimal digits correct,
|
|
but making it difficult to reason about precision and computational uncertainty, for example see [*https://svn.boost.org/trac10/ticket/12133].
|
|
It also has a fast but imprecise division operator giving surprising results sometimes, see [*https://svn.boost.org/trac10/ticket/11178].
|
|
|
|
`cpp_bin_` is correctly/exactly rounded making it possible to reason about both the precision and rounding of the results.]]
|
|
] [/variablelist]
|
|
|
|
[endsect]
|
|
|
|
[section:ack Acknowledgements]
|
|
|
|
This library would not have happened without:
|
|
|
|
* Christopher Kormanyos' C++ decimal number code.
|
|
* Paul Bristow for patiently testing, and commenting on the library.
|
|
* All the folks at GMP, MPFR and libtommath, for providing the "guts" that makes this library work.
|
|
* [@http://www-cs-faculty.stanford.edu/~uno/taocp.html "The Art Of Computer Programming"],
|
|
Donald E. Knuth, Volume 2: Seminumerical Algorithms, Third Edition
|
|
(Reading, Massachusetts: Addison-Wesley, 1997), xiv+762pp. ISBN 0-201-89684-2
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:indexes Indexes]
|
|
|
|
'''
|
|
<index type="function_name">
|
|
<title>Function Index</title>
|
|
</index>
|
|
|
|
<index type="class_name">
|
|
<title>Class Index</title>
|
|
</index>
|
|
|
|
<index type="typedef_name">
|
|
<title>Typedef Index</title>
|
|
</index>
|
|
|
|
<index/>
|
|
'''
|
|
|
|
[endsect]
|