mirror of
https://github.com/boostorg/multiprecision.git
synced 2026-07-21 13:23:49 +00:00
9d16324b79
Fix doc Jamfile. Add redirect index.html. [SVN r81553]
3507 lines
194 KiB
Plaintext
3507 lines
194 KiB
Plaintext
[/
|
|
Copyright 2011 John Maddock.
|
|
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.5]
|
|
[copyright 2002-2012 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) $]
|
|
]
|
|
|
|
[include html4_symbols.qbk]
|
|
[import ../example/gmp_snips.cpp]
|
|
[import ../example/mpfr_snips.cpp]
|
|
[import ../example/cpp_dec_float_snips.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]
|
|
|
|
[template mpfr[] [@http://www.mpfr.org MPFR]]
|
|
[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.org/?page=features&newsitems=5&whatfile=ltm libtommath]]
|
|
|
|
[template super[x]'''<superscript>'''[x]'''</superscript>''']
|
|
[template sub[x]'''<subscript>'''[x]'''</subscript>''']
|
|
|
|
[template equation[name] '''<inlinemediaobject>
|
|
<imageobject role="html">
|
|
<imagedata fileref="../'''[name]'''.png"></imagedata>
|
|
</imageobject>
|
|
<imageobject role="print">
|
|
<imagedata fileref="../'''[name]'''.svg"></imagedata>
|
|
</imageobject>
|
|
</inlinemediaobject>''']
|
|
|
|
[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_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]]
|
|
|
|
[section:intro Introduction]
|
|
|
|
The Multiprecision Library provides [link boost_multiprecision.tut.ints integer],
|
|
[link boost_multiprecision.tut.rational rational]
|
|
and [link boost_multiprecision.tut.floats floating-point] 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 the
|
|
built-in types 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 and
|
|
floating-point types. Boost.Multiprecision provides a selection
|
|
of back ends provided off-the-rack in including
|
|
interfaces to GMP, MPFR, MPIR, 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-template-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).
|
|
|
|
Should you just wish to cut to the chase and use a fully Boost-licensed number type, then skip to
|
|
__cpp_int for multiprecision integers, __cpp_dec_float for multiprecision floating point types
|
|
and __cpp_rational for rational types.
|
|
|
|
The library is often used via one of the predefined typedefs: for example 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.
|
|
|
|
Alternatively, you can compose your own 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 float 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&& a, const number& 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]
|
|
|
|
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 optimises the code, and whether it supports
|
|
rvalue references. The number of 11 temporaries was generated with Visual C++ 10]
|
|
|
|
[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.
|
|
|
|
One other potential pitfall that's only possible 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`.
|
|
|
|
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: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] or [link boost_multiprecision.tut.rational rational]).
|
|
* Which back-end do I want to perform the actual arithmetic (Boost-supplied, GMP, MPFR, 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 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_adapter<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_adapter<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 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
|
|
characterists 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 senario" with only minor performance degradation even if most of the time
|
|
the arithmetic could in fact be done with a narrower type.
|
|
* 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.
|
|
|
|
|
|
[h5 Example:]
|
|
|
|
[cpp_int_eg]
|
|
|
|
[endsect]
|
|
|
|
[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: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:egs Examples]
|
|
|
|
[import ../example/integer_examples.cpp]
|
|
|
|
[section:factorials Factorials]
|
|
[FAC1]
|
|
[endsect]
|
|
|
|
[section:bitops Bit Operations]
|
|
[BITOPS]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:floats Floating Point Numbers]
|
|
|
|
The following back-ends provide floating point arithmetic:
|
|
|
|
[table
|
|
[[Backend Type][Header][Radix][Dependencies][Pros][Cons]]
|
|
[[`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.]]
|
|
]
|
|
|
|
[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 truely huge exponent range.
|
|
|
|
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_float.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 guarentee 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 `mpf_t` via the data() member function of `gmp_float`.
|
|
|
|
Things you should know when using this type:
|
|
|
|
* A default constructed `mpfr_float_backend` is set to a NaN (this is 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.
|
|
|
|
[h5 [mpfr] example:]
|
|
|
|
[mpfr_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]
|
|
|
|
[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_adapter`][boost/multiprecision/rational_adapter.hpp][N/A][none][All C++ adapter 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_adapter<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_adapter rational_adapter]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <class IntBackend>
|
|
class rational_adpater;
|
|
|
|
}}
|
|
|
|
The class template `rational_adapter` 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_adapter<MyIntegerBackend> > MyRational;
|
|
|
|
MyRational r = 2;
|
|
r /= 3;
|
|
MyInt i = numerator(r);
|
|
assert(i == 2);
|
|
|
|
[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.template convert_to<int>(); // sets i to 2
|
|
|
|
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 explict
|
|
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 implict 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. However, since Boost.Random is unaware
|
|
of [@http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic arbitrary precision] numbers, it's necessary to include the header:
|
|
|
|
#include <boost/multiprecision/random.hpp>
|
|
|
|
In order to act as a bridge between the two libraries.
|
|
|
|
Integers with /N/ random bits are generated using `independent_bits_engine`:
|
|
|
|
[random_eg1]
|
|
|
|
Alternatively we can generate integers in a given range using `uniform_int_distribution`, this will
|
|
invoke the underlying engine multiple times to build up the required number of bits in the result:
|
|
|
|
[random_eg2]
|
|
|
|
Floating point values in \[0,1) are generated using `uniform_01`, the trick here is to ensure
|
|
that the underlying generator produces as many random bits as there are digits in the floating
|
|
point type. As above `independent_bits_engine` can be used for this purpose, note that we also have to
|
|
convert decimal digits (in the floating point type) to bits (in the random number generator):
|
|
|
|
[random_eg3]
|
|
|
|
Finally, we can modify the above example to produce numbers distributed according to some distribution:
|
|
|
|
[random_eg4]
|
|
|
|
[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 prime with probability ['0.25^trials]. 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 is limited support for `constexpr` in the library, currently the `number` front end supports `constexpr`
|
|
on default construction and all forwarding constructors, but not on any of the non-member operators. So if
|
|
some type `B` is a literal type, then `number<B>` is also a literal type, and you will be able to
|
|
compile-time-construct such a type from any literal that `B` is compile-time-constructible from.
|
|
However, you will not be able to perform compile-time arithmetic on such types.
|
|
|
|
Currently the only backend type provided by the library that is also a literal type are instantiations
|
|
of `cpp_int_backend` where the Allocator parameter is type `void`, and the Checked parameter is
|
|
`boost::multiprecision::unchecked`.
|
|
|
|
For example:
|
|
|
|
using namespace boost::multiprecision;
|
|
|
|
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; // Error, checked type is not a literal type as we need runtime error checking.
|
|
constexpr cpp_int l = 2; // Error, type is not a literal as it performs memory management.
|
|
|
|
[endsect]
|
|
|
|
[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: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]
|
|
|
|
[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
|
|
{
|
|
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;
|
|
// 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);
|
|
|
|
// Non-member function standard library support:
|
|
``['unmentionable-expression-template-type]`` abs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` fabs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sqrt (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` floor (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ceil (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` trunc (const ``['number-or-expression-template-type]``&);
|
|
``['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]`` round (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` iround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` lround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` llround(const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` exp (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log10 (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cos (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sin (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` acos (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` asin (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` atan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cosh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sinh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tanh (const ``['number-or-expression-template-type]``&);
|
|
|
|
``['unmentionable-expression-template-type]`` ldexp (const ``['number-or-expression-template-type]``&, int);
|
|
``['unmentionable-expression-template-type]`` frexp (const ``['number-or-expression-template-type]``&, int*);
|
|
``['unmentionable-expression-template-type]`` pow (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]`` atan2 (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]`` 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);
|
|
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);
|
|
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 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`.
|
|
|
|
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`
|
|
|
|
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]`` fabs (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sqrt (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` floor (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` ceil (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` trunc (const ``['number-or-expression-template-type]``&);
|
|
``['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]`` round (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` iround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` lround (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` llround(const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` exp (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` log10 (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cos (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sin (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` acos (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` asin (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` atan (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` cosh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` sinh (const ``['number-or-expression-template-type]``&);
|
|
``['unmentionable-expression-template-type]`` tanh (const ``['number-or-expression-template-type]``&);
|
|
|
|
``['unmentionable-expression-template-type]`` ldexp (const ``['number-or-expression-template-type]``&, int);
|
|
``['unmentionable-expression-template-type]`` frexp (const ``['number-or-expression-template-type]``&, int*);
|
|
``['unmentionable-expression-template-type]`` pow (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]`` atan2 (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.
|
|
|
|
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 deterimined 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 transcendal functions is generally a few epsilon. Note however, that the trigonmetrical
|
|
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]`` 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.
|
|
|
|
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 index of the least significant bit that is set to 1.
|
|
|
|
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_adapter<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_adapter<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
|
|
|
|
Class template `cpp_int_backend` fulfills 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` fulfills 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` fulfills 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` fulfills 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` fulfills 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_dec_ref cpp_dec_float]
|
|
|
|
namespace boost{ namespace multiprecision{
|
|
|
|
template <unsigned Digits10>
|
|
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` fulfills 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. Note that this type does not ever perform any dynamic memory allocation, as a result the `Digits10`
|
|
template argument should not be set too high or the class's size will grow unreasonably large.
|
|
|
|
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.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, `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.
|
|
|
|
[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 interpretted as a valid number.]]
|
|
[[`b.swap(b)`][`void`][Swaps the contents of its arguments.][`noexcept`]]
|
|
[[`cb.str(ui, bb)`][`std::string`][Returns the string representation of `b` with `ui` digits and in scientific format if `bb` is `true`.
|
|
If `ui` 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_rational` or `number_kind_fixed_point`.
|
|
Defaults to `number_kind_floating_point`.][[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 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 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_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]]]
|
|
|
|
[[['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_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_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]]]
|
|
]
|
|
|
|
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.]
|
|
|
|
[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_adapter.hpp][Defines the `rational_adapter` 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 architypes 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.]]
|
|
[[defail/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_perfromance.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 Perfomance]
|
|
|
|
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 Perfomance]
|
|
|
|
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.22306 (0.0279933s)][1.15878 (0.038341s)][1.24006 (0.0562258s)][1.32055 (0.0925091s)]]
|
|
[[cpp_int(fixed)][1.56093 (0.0357264s)][1.71757 (0.05683s)][1.66497 (0.0754916s)][1.70376 (0.119354s)]]
|
|
[[gmp_int][1.98788 (0.0454986s)][1.37882 (0.0456216s)][1.14898 (0.0520959s)][[*1] (0.0700532s)]]
|
|
[[tommath_int][[*1] (0.022888s)][[*1] (0.0330875s)][[*1] (0.0453411s)][1.07021 (0.074972s)]]
|
|
]
|
|
[table Operator +(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0162581s)][[*1] (0.0196602s)][[*1] (0.0305476s)][[*1] (0.0421105s)]]
|
|
[[cpp_int(fixed)][1.3852 (0.0225207s)][1.84835 (0.036339s)][1.6111 (0.0492153s)][1.63014 (0.068646s)]]
|
|
[[gmp_int][1.95525 (0.0317886s)][2.2217 (0.0436791s)][2.21508 (0.0676653s)][2.58759 (0.108965s)]]
|
|
[[tommath_int][13.603 (0.221158s)][11.5797 (0.227659s)][7.86674 (0.24031s)][6.36923 (0.268212s)]]
|
|
]
|
|
[table Operator +(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0269712s)][[*1] (0.0296213s)][[*1] (0.0380242s)][[*1] (0.045841s)]]
|
|
[[cpp_int(fixed)][1.38342 (0.0373126s)][1.51165 (0.0447769s)][1.54533 (0.05876s)][1.3971 (0.0640443s)]]
|
|
[[gmp_int][26.7163 (0.72057s)][24.0631 (0.712781s)][19.6009 (0.745307s)][17.6547 (0.809308s)]]
|
|
[[tommath_int][19.7493 (0.532664s)][18.2944 (0.541905s)][14.9127 (0.567043s)][12.9059 (0.591619s)]]
|
|
]
|
|
[table Operator +=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.16166 (0.020334s)][1.15312 (0.0204789s)][1.21086 (0.0216179s)][1.28088 (0.0229569s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0175043s)][[*1] (0.0177595s)][[*1] (0.0178534s)][[*1] (0.0179228s)]]
|
|
[[gmp_int][39.0852 (0.684159s)][38.7246 (0.68773s)][38.2555 (0.68299s)][37.6736 (0.675217s)]]
|
|
[[tommath_int][30.5872 (0.535408s)][29.371 (0.521614s)][30.3387 (0.541648s)][31.8346 (0.570565s)]]
|
|
]
|
|
[table Operator -
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.12975 (0.0308979s)][[*1] (0.0392305s)][1.05392 (0.0543957s)][1.18166 (0.0860767s)]]
|
|
[[cpp_int(fixed)][1.36853 (0.0374283s)][1.45987 (0.0572717s)][1.44606 (0.0746349s)][1.55935 (0.11359s)]]
|
|
[[gmp_int][1.53173 (0.0418917s)][1.17956 (0.0462749s)][1.13609 (0.0586365s)][[*1] (0.0728442s)]]
|
|
[[tommath_int][[*1] (0.0273493s)][1.07293 (0.0420917s)][[*1] (0.0516126s)][1.0985 (0.0800191s)]]
|
|
]
|
|
[table Operator -(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0146171s)][[*1] (0.0172176s)][[*1] (0.023655s)][[*1] (0.0313105s)]]
|
|
[[cpp_int(fixed)][1.49086 (0.021792s)][1.94917 (0.03356s)][1.89657 (0.0448632s)][1.82658 (0.057191s)]]
|
|
[[gmp_int][2.16301 (0.0316169s)][2.55059 (0.0439151s)][2.67983 (0.0633913s)][3.27949 (0.102682s)]]
|
|
[[tommath_int][14.0691 (0.20565s)][12.527 (0.215684s)][9.43355 (0.22315s)][7.64671 (0.239422s)]]
|
|
]
|
|
[table Operator -(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0265242s)][[*1] (0.0295275s)][[*1] (0.0377737s)][[*1] (0.0450106s)]]
|
|
[[cpp_int(fixed)][1.2627 (0.033492s)][1.47472 (0.0435449s)][1.47468 (0.055704s)][1.40667 (0.0633151s)]]
|
|
[[gmp_int][26.0595 (0.691208s)][23.3957 (0.690817s)][18.9344 (0.715223s)][16.9593 (0.763349s)]]
|
|
[[tommath_int][19.26 (0.510855s)][17.6236 (0.52038s)][13.9134 (0.52556s)][12.2359 (0.550746s)]]
|
|
]
|
|
[table Operator -=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.28589 (0.0210146s)][1.3505 (0.0222463s)][1.34427 (0.0237863s)][1.22787 (0.0230902s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0163425s)][[*1] (0.0164727s)][[*1] (0.0176946s)][[*1] (0.0188051s)]]
|
|
[[gmp_int][41.0201 (0.670371s)][41.4726 (0.683165s)][37.9503 (0.671514s)][35.6021 (0.669502s)]]
|
|
[[tommath_int][32.6952 (0.534322s)][31.4882 (0.518695s)][29.3988 (0.5202s)][29.1175 (0.547558s)]]
|
|
]
|
|
[table Operator *
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.13172 (0.0766099s)][1.59509 (0.20993s)][1.40998 (0.70643s)][1.70758 (2.66895s)]]
|
|
[[cpp_int(fixed)][[*1] (0.067693s)][1.27132 (0.167319s)][[*1] (0.50102s)][[*1] (1.563s)]]
|
|
[[gmp_int][1.01718 (0.0688559s)][[*1] (0.13161s)][1.13221 (0.567258s)][1.02292 (1.59883s)]]
|
|
[[tommath_int][1.6793 (0.113677s)][2.66959 (0.351345s)][2.01091 (1.00751s)][2.05812 (3.21684s)]]
|
|
]
|
|
[table Operator *(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0228822s)][1.19988 (0.0332404s)][1.13882 (0.0416226s)][1.2711 (0.0665655s)]]
|
|
[[cpp_int(fixed)][1.33157 (0.0304692s)][1.6546 (0.0458376s)][1.72684 (0.063114s)][1.83178 (0.0959269s)]]
|
|
[[gmp_int][1.00858 (0.0230786s)][[*1] (0.0277032s)][[*1] (0.0365488s)][[*1] (0.0523682s)]]
|
|
[[tommath_int][10.8491 (0.248252s)][9.88511 (0.273849s)][8.95509 (0.327298s)][8.04172 (0.421131s)]]
|
|
]
|
|
[table Operator *(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0574926s)][[*1] (0.0876613s)][[*1] (0.146194s)][[*1] (0.258556s)]]
|
|
[[cpp_int(fixed)][1.12247 (0.0645337s)][1.24471 (0.109113s)][1.19748 (0.175065s)][1.17442 (0.303653s)]]
|
|
[[gmp_int][12.271 (0.705488s)][8.23054 (0.7215s)][5.28668 (0.772883s)][3.09816 (0.801047s)]]
|
|
[[tommath_int][10.2751 (0.590743s)][7.36707 (0.645807s)][4.88979 (0.71486s)][3.43724 (0.888719s)]]
|
|
]
|
|
[table Operator *=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][114.922 (7.57662s)][70.5882 (7.61458s)][44.3157 (7.67791s)][26.2881 (7.81595s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0659286s)][[*1] (0.107873s)][[*1] (0.173255s)][[*1] (0.297319s)]]
|
|
[[gmp_int][47.9828 (3.16344s)][29.4972 (3.18196s)][18.1719 (3.14838s)][10.6941 (3.17956s)]]
|
|
[[tommath_int][284.199 (18.7368s)][173.129 (18.676s)][109.052 (18.8938s)][64.5866 (19.2028s)]]
|
|
]
|
|
[table Operator /
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][2.71618 (0.616086s)][2.09988 (0.737246s)][1.65898 (0.94343s)][1.49441 (1.44418s)]]
|
|
[[cpp_int(fixed)][[*1] (0.226821s)][[*1] (0.35109s)][[*1] (0.56868s)][[*1] (0.966385s)]]
|
|
[[gmp_int][3.82134 (0.866761s)][2.75998 (0.969001s)][1.93226 (1.09884s)][1.34132 (1.29623s)]]
|
|
[[tommath_int][13.2978 (3.01622s)][11.3314 (3.97833s)][9.94138 (5.65347s)][13.3423 (12.8938s)]]
|
|
]
|
|
[table Operator /(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][4.15094 (0.23911s)][3.57962 (0.356615s)][3.11624 (0.578256s)][2.82967 (1.00414s)]]
|
|
[[cpp_int(fixed)][2.42806 (0.139865s)][2.54164 (0.253208s)][2.43025 (0.450962s)][2.37209 (0.841768s)]]
|
|
[[gmp_int][[*1] (0.0576038s)][[*1] (0.0996238s)][[*1] (0.185562s)][[*1] (0.354863s)]]
|
|
[[tommath_int][36.3133 (2.09179s)][28.2731 (2.81668s)][21.8589 (4.05618s)][25.8061 (9.15762s)]]
|
|
]
|
|
[table Operator /(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.53953 (0.716927s)][1.40156 (1.65075s)][2.59584 (3.57744s)][4.58524 (8.3789s)]]
|
|
[[cpp_int(fixed)][[*1] (0.465679s)][1.09556 (1.29034s)][2.2858 (3.15016s)][4.40115 (8.0425s)]]
|
|
[[gmp_int][2.25405 (1.04967s)][[*1] (1.17779s)][[*1] (1.37814s)][[*1] (1.82736s)]]
|
|
[[tommath_int][5.03884 (2.34648s)][2.63459 (3.103s)][3.67287 (5.06174s)][6.77479 (12.38s)]]
|
|
]
|
|
[table Operator /=(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.78744 (0.0586752s)][1.74065 (0.0616578s)][1.66814 (0.0740436s)][1.36231 (0.126362s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0328264s)][[*1] (0.0354222s)][[*1] (0.0443871s)][[*1] (0.0927553s)]]
|
|
[[gmp_int][21.2392 (0.697207s)][19.3517 (0.68548s)][15.2936 (0.678837s)][7.37138 (0.683734s)]]
|
|
[[tommath_int][32.8142 (1.07717s)][30.5556 (1.08235s)][24.7236 (1.09741s)][12.4072 (1.15084s)]]
|
|
]
|
|
[table Operator %
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.86833 (0.37472s)][1.43076 (0.491332s)][1.30757 (0.708055s)][1.2528 (1.15842s)]]
|
|
[[cpp_int(fixed)][[*1] (0.200565s)][[*1] (0.343407s)][[*1] (0.541503s)][[*1] (0.924662s)]]
|
|
[[gmp_int][3.22603 (0.647027s)][2.08249 (0.715143s)][1.5148 (0.82027s)][1.09519 (1.01268s)]]
|
|
[[tommath_int][15.4642 (3.10158s)][11.5534 (3.9675s)][10.5164 (5.69467s)][13.8962 (12.8493s)]]
|
|
]
|
|
[table Operator %(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.80079 (0.106617s)][1.96413 (0.207216s)][2.09096 (0.395682s)][2.14767 (0.776873s)]]
|
|
[[cpp_int(fixed)][1.73532 (0.10274s)][1.92036 (0.202599s)][2.02172 (0.382579s)][2.07328 (0.749963s)]]
|
|
[[gmp_int][[*1] (0.0592053s)][[*1] (0.1055s)][[*1] (0.189234s)][[*1] (0.361727s)]]
|
|
[[tommath_int][35.6993 (2.11359s)][25.3086 (2.67007s)][21.2701 (4.02504s)][25.8662 (9.3565s)]]
|
|
]
|
|
[table Operator construct
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.17135 (0.00274853s)][[*1] (0.00275161s)][[*1] (0.00275161s)][[*1] (0.00344359s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00234646s)][1.54518 (0.00425173s)][2.2494 (0.00618947s)][1.73247 (0.00596591s)]]
|
|
[[gmp_int][85.6802 (0.201045s)][72.6635 (0.199941s)][78.1286 (0.214979s)][58.3553 (0.200952s)]]
|
|
[[tommath_int][87.9831 (0.206449s)][74.8522 (0.205964s)][74.8918 (0.206073s)][63.4572 (0.218521s)]]
|
|
]
|
|
[table Operator construct(unsigned)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.43934 (0.00268554s)][[*1] (0.00286887s)][[*1] (0.00283465s)][[*1] (0.00290638s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00186581s)][1.7597 (0.00504834s)][2.07419 (0.00587959s)][1.89871 (0.00551837s)]]
|
|
[[gmp_int][125.861 (0.234832s)][72.7068 (0.208586s)][75.5147 (0.214058s)][71.2679 (0.207131s)]]
|
|
[[tommath_int][240.568 (0.448854s)][155.552 (0.446257s)][157.598 (0.446734s)][160.728 (0.467137s)]]
|
|
]
|
|
[table Operator construct(unsigned long long)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][2.3528 (0.00771495s)][1.61678 (0.00717424s)][1.12087 (0.00715985s)][1.2104 (0.0078878s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00327905s)][[*1] (0.00443737s)][[*1] (0.00638775s)][[*1] (0.00651668s)]]
|
|
[[gmp_int][222.775 (0.730489s)][165.447 (0.734148s)][114.708 (0.732725s)][112.162 (0.730926s)]]
|
|
[[tommath_int][215.962 (0.70815s)][157.945 (0.700858s)][109.582 (0.699985s)][111.909 (0.729275s)]]
|
|
]
|
|
[table Operator str
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.46938 (0.00196575s)][1.37205 (0.00331355s)][1.5689 (0.00862952s)][1.57176 (0.0237239s)]]
|
|
[[cpp_int(fixed)][[*1] (0.00133781s)][[*1] (0.00241504s)][[*1] (0.00550035s)][1.20619 (0.0182059s)]]
|
|
[[gmp_int][1.65482 (0.00221383s)][1.38972 (0.00335622s)][1.13845 (0.0062619s)][[*1] (0.0150938s)]]
|
|
[[tommath_int][13.9845 (0.0187087s)][18.3179 (0.0442384s)][23.3489 (0.128427s)][25.3273 (0.382285s)]]
|
|
]
|
|
[table Operator gcd
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][2.03241 (5.06795s)][1.89904 (11.3002s)][1.99735 (27.4027s)][2.20708 (73.7574s)]]
|
|
[[cpp_int(fixed)][1.67874 (4.18605s)][1.70044 (10.1184s)][1.96475 (26.9554s)][2.28347 (76.31s)]]
|
|
[[gmp_int][[*1] (2.49357s)][[*1] (5.95047s)][[*1] (13.7195s)][[*1] (33.4185s)]]
|
|
[[tommath_int][5.01832 (12.5135s)][4.41659 (26.2808s)][4.08042 (55.9814s)][3.97901 (132.972s)]]
|
|
]
|
|
[table Operator &
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.00344 (0.0315529s)][[*1] (0.0426295s)][[*1] (0.0543214s)][1.06624 (0.0835064s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0314446s)][1.0808 (0.046074s)][1.06116 (0.0576436s)][[*1] (0.0783186s)]]
|
|
[[gmp_int][1.78372 (0.0560885s)][1.58661 (0.0676363s)][1.5738 (0.0854908s)][1.83409 (0.143644s)]]
|
|
[[tommath_int][4.08054 (0.128311s)][3.50852 (0.149567s)][2.88826 (0.156894s)][4.45879 (0.349206s)]]
|
|
]
|
|
[table Operator &(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0367605s)][[*1] (0.0485394s)][[*1] (0.0650023s)][[*1] (0.099751s)]]
|
|
[[cpp_int(fixed)][1.00324 (0.0368795s)][1.06734 (0.0518081s)][1.05192 (0.0683771s)][1.05296 (0.105034s)]]
|
|
[[gmp_int][4.00058 (0.147063s)][3.02928 (0.147039s)][2.22221 (0.144449s)][1.45749 (0.145386s)]]
|
|
[[tommath_int][8.83732 (0.324864s)][6.95191 (0.337442s)][5.42556 (0.352674s)][6.10829 (0.609309s)]]
|
|
]
|
|
[table Operator |
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0312723s)][[*1] (0.0428385s)][[*1] (0.0528083s)][[*1] (0.0827344s)]]
|
|
[[cpp_int(fixed)][1.0311 (0.0322449s)][1.20267 (0.0515207s)][1.27028 (0.0670814s)][1.19432 (0.0988112s)]]
|
|
[[gmp_int][1.55273 (0.0485576s)][1.4656 (0.0627839s)][1.66721 (0.0880424s)][1.67004 (0.13817s)]]
|
|
[[tommath_int][4.15311 (0.129877s)][3.39008 (0.145226s)][2.88739 (0.152478s)][4.20575 (0.34796s)]]
|
|
]
|
|
[table Operator |(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][1.01685 (0.030066s)][[*1] (0.0360965s)][[*1] (0.0402109s)][[*1] (0.0527074s)]]
|
|
[[cpp_int(fixed)][[*1] (0.0295677s)][1.50234 (0.0542292s)][1.52609 (0.0613656s)][1.37526 (0.0724863s)]]
|
|
[[gmp_int][4.84414 (0.14323s)][3.99297 (0.144132s)][3.85375 (0.154963s)][2.91129 (0.153447s)]]
|
|
[[tommath_int][10.8218 (0.319975s)][9.05203 (0.326747s)][8.32597 (0.334795s)][10.948 (0.577039s)]]
|
|
]
|
|
[table Operator ^
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0311003s)][[*1] (0.0430909s)][[*1] (0.0530915s)][[*1] (0.0842599s)]]
|
|
[[cpp_int(fixed)][1.04721 (0.0325686s)][1.18557 (0.0510874s)][1.25714 (0.0667433s)][1.14462 (0.0964459s)]]
|
|
[[gmp_int][1.59277 (0.0495356s)][1.47967 (0.0637601s)][1.73243 (0.0919772s)][1.68499 (0.141977s)]]
|
|
[[tommath_int][4.17425 (0.12982s)][3.41013 (0.146946s)][2.8988 (0.153902s)][4.17074 (0.351426s)]]
|
|
]
|
|
[table Operator ^(int)
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0290428s)][[*1] (0.0360261s)][[*1] (0.0409722s)][[*1] (0.0541785s)]]
|
|
[[cpp_int(fixed)][1.01484 (0.0294736s)][1.4898 (0.0536716s)][1.34782 (0.0552234s)][1.35054 (0.0731703s)]]
|
|
[[gmp_int][4.94574 (0.143638s)][4.05569 (0.146111s)][3.65257 (0.149654s)][2.89039 (0.156597s)]]
|
|
[[tommath_int][10.8939 (0.316389s)][9.21322 (0.331916s)][8.17995 (0.335151s)][10.6902 (0.579178s)]]
|
|
]
|
|
[table Operator <<
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0253777s)][1.04239 (0.034484s)][[*1] (0.0420979s)][[*1] (0.0623485s)]]
|
|
[[cpp_int(fixed)][1.05039 (0.0266563s)][1.40679 (0.0465388s)][1.34077 (0.0564434s)][1.20319 (0.0750171s)]]
|
|
[[gmp_int][1.0359 (0.0262888s)][[*1] (0.0330815s)][1.1625 (0.0489388s)][1.16511 (0.0726428s)]]
|
|
[[tommath_int][1.65904 (0.0421025s)][2.11201 (0.0698686s)][2.36727 (0.0996572s)][2.701 (0.168403s)]]
|
|
]
|
|
[table Operator >>
|
|
[[Backend][128 Bits][256 Bits][512 Bits][1024 Bits]]
|
|
[[cpp_int][[*1] (0.0221035s)][1.0337 (0.0313761s)][1.03419 (0.0355718s)][1.20366 (0.0453508s)]]
|
|
[[cpp_int(fixed)][1.1036 (0.0243933s)][1.12323 (0.0340936s)][1.40181 (0.0482162s)][1.69985 (0.0640463s)]]
|
|
[[gmp_int][1.30456 (0.0288354s)][[*1] (0.0303532s)][[*1] (0.0343958s)][[*1] (0.0376776s)]]
|
|
[[tommath_int][10.5766 (0.233779s)][9.0959 (0.27609s)][8.6249 (0.29666s)][13.6818 (0.515498s)]]
|
|
]
|
|
|
|
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 Perfomance]
|
|
|
|
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]
|
|
|
|
[section:hist History]
|
|
|
|
[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 adapter back-end for complex number types.
|
|
* Add a back-end for MPFR interval arithmetic.
|
|
* Add better multiplication routines (Karatsuba, FFT etc) to cpp_int_backend.
|
|
* Add assembly level routines to cpp_int_backend.
|
|
* Add an all C++ Boost licenced binary floating point type.
|
|
* 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 convertion.
|
|
* 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 optimimization, 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
|
|
contexpr 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 templare 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 deamed not to be practical: these algorithms are intimately
|
|
tied to the actual data representation used.]]
|
|
]
|
|
|
|
[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]
|
|
|
|
[include ../../../tools/auto_index/include/auto_index_helpers.qbk]
|
|
[named_index function_name Function Index]
|
|
[named_index class_name Class Index]
|
|
[named_index typedef_name Typedef Index]
|
|
[index]
|
|
|
|
[endsect]
|
|
|