Boost.Multiprecision Overview Guide
Boost.Multiprecision Overview Guide
Multiprecision
John Maddock
Christopher Kormanyos
Copyright © 2002-2013 John Maddock and Christopher Kormanyos
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
[Link]
Table of Contents
Introduction .......................................................................................................................................................... 3
Tutorial ................................................................................................................................................................ 9
Integer Types ................................................................................................................................................. 9
cpp_int ................................................................................................................................................. 9
gmp_int .............................................................................................................................................. 12
tom_int ............................................................................................................................................... 13
Examples ............................................................................................................................................ 15
Factorials .................................................................................................................................... 15
Bit Operations ............................................................................................................................. 16
Floating Point Numbers ................................................................................................................................. 17
cpp_bin_float ...................................................................................................................................... 18
cpp_dec_float ...................................................................................................................................... 20
gmp_float ........................................................................................................................................... 21
mpfr_float ........................................................................................................................................... 23
float128 .............................................................................................................................................. 25
Examples ............................................................................................................................................ 26
Area of Circle .............................................................................................................................. 26
Defining a Special Function. ........................................................................................................... 27
Calculating a Derivative ................................................................................................................. 30
Calculating an Integral .................................................................................................................. 32
Polynomial Evaluation .................................................................................................................. 34
Interval Number Types .................................................................................................................................. 36
mpfi_float ........................................................................................................................................... 36
Rational Number Types ................................................................................................................................. 39
cpp_rational ........................................................................................................................................ 40
gmp_rational ....................................................................................................................................... 41
tommath_rational ................................................................................................................................. 42
Use With [Link] ........................................................................................................................ 43
rational_adaptor ................................................................................................................................... 43
Miscellaneous Number Types. ........................................................................................................................ 44
logged_adaptor .................................................................................................................................... 44
debug_adaptor ..................................................................................................................................... 46
Visual C++ Debugger Visualizers ............................................................................................................ 48
Constructing and Interconverting Between Number Types .................................................................................... 51
Generating Random Numbers ......................................................................................................................... 53
Primality Testing .......................................................................................................................................... 55
Literal Types and constexpr Support ............................................................................................................. 56
Rounding Rules for Conversions ..................................................................................................................... 58
Mixed Precision Arithmetic ............................................................................................................................ 59
Generic Integer Operations ............................................................................................................................. 61
[Link] Support ............................................................................................................................ 62
Numeric Limits ............................................................................................................................................ 62
Introduction
The Multiprecision Library provides integer, rational and 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 [Link]. The Multiprecision types can also interoperate with the
built-in types in C++ using clearly defined conversion rules. This allows [Link] to be used for all kinds of mathemat-
ical 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. [Link] 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 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.
• 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 require-
ments 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 arbitrary precision integer type using GMP
as the underlying implementation then you could use:
#include <boost/multiprecision/[Link]> // Defines the wrappers around the GMP library's types
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:
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:
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>
However conversions that are inherently lossy are either declared explicit or else forbidden altogether:
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:
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.
Expression Templates
Class number is expression-template-enabled: that means that rather than having a multiplication operator that looks like this:
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:
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 mp-
fr_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. 1
1
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;
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 numbers 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:
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 [Link] library will automatically convert expression-template arguments to the underlying number type without you
having to do anything, so:
Will work just fine, with the a + delta expression template argument getting converted to an mpfr_float_100 internally by the
[Link] 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:
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 work-
space). 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):
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.
Tutorial
In order to use this library you need to make two choices:
• Which back-end do I want to perform the actual arithmetic (Boost-supplied, GMP, MPFR, Tommath etc)?
Integer Types
The following back-ends provide integer arithmetic:
cpp_int
#include <boost/multiprecision/cpp_int.hpp>
}} // namespaces
10
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 arbitrary precision integer types, and
both signed and unsigned types. There are five template arguments:
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 per-
formed: 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 arbitrary precision types this parameter must
be signed_magnitude. For fixed precision types then this type may be either signed_magnitude or un-
signed_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:
Numeric overflow in fixed precision Throws a std::overflow_error. Performs arithmetic modulo 2MaxBits
arithmetic
Constructing an integer from a value that Throws a std::range_error. Converts the value modulo 2MaxBits,
can not be represented in the target type signed to unsigned conversions extract
the last MaxBits bits of the 2's comple-
ment representation of the input value.
Unsigned subtraction yielding a negative Throws a std::range_error. Yields the value that would result from
value. treating the unsigned type as a 2's comple-
ment signed type.
Attempting a bitwise operation on a neg- Throws a std::range_error Yields the value, but not the bit pattern,
ative value. that would result from performing the
operation on a 2's complement integer
type.
• 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
11
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.
• 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 characteristics as a 128-bit integer,
rather than being 4 times slower for addition and 16 times slower for multiplication (assuming the values involved would always
fit in 128 bits). Typically this means you can use an integer type wide enough for the "worst case scenario" with only minor per-
formance 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.
• Fixed precision cpp_int's have some support for constexpr values and user-defined literals, see here for the full description.
For example 0xfffff_cppi1024 specifies a 1024-bit integer with the value 0xffff. This can be used to generate compile time
constants that are too large to fit into any built in number type.
Example:
#include <boost/multiprecision/cpp_int.hpp>
int128_t v = 1;
gmp_int
#include <boost/multiprecision/[Link]>
12
class gmp_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:
• 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.
• 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_ints 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.
• 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.
Example:
#include <boost/multiprecision/[Link]>
mpz_int v = 1;
// Do some arithmetic:
for(unsigned i = 1; i <= 1000; ++i)
v *= i;
tom_int
#include <boost/multiprecision/[Link]>
13
class tommath_int;
}} // namespaces
The tommath_int back-end is used via the typedef boost::multiprecision::tom_int. It acts as a thin wrapper around the
libtommath tom_int to provide an integer type that is a drop-in replacement for the native C++ integer types, but with unlimited
precision.
• Default constructed objects have the value zero (this is libtommath'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.
Example:
#include <boost/multiprecision/[Link]>
boost::multiprecision::tom_int v = 1;
// Do some arithmetic:
for(unsigned i = 1; i <= 1000; ++i)
v *= i;
try{
std::cout << std::hex << -v << std::endl; // Ooops! can't print a negative value in hex format!
}
catch(const std::runtime_error& e)
{
std::cout << [Link]() << std::endl;
}
try{
// v is not a 2's complement type, bitwise operations are only supported
// on positive values:
v = -v & 2;
}
catch(const std::runtime_error& e)
{
std::cout << [Link]() << std::endl;
}
14
Examples
Factorials
In this simple example, we'll write a routine to print out all of the factorials which will fit into a 128-bit integer. At the end of the
routine we do some fancy iostream formatting of the results:
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
#include <iomanip>
#include <vector>
void print_factorials()
{
using boost::multiprecision::cpp_int;
//
// Print all the factorials that will fit inside a 128-bit integer.
//
// Begin by building a big table of factorials, once we know just how
// large the largest is, we'll be able to "pretty format" the results.
//
// Calculate the largest number that will fit inside 128 bits, we could
// also have used numeric_limits<int128_t>::max() for this value:
cpp_int limit = (cpp_int(1) << 128) - 1;
//
// Our table of values:
std::vector<cpp_int> results;
//
// Initial values:
unsigned i = 1;
cpp_int factorial = 1;
//
// Cycle through the factorials till we reach the limit:
while(factorial < limit)
{
results.push_back(factorial);
++i;
factorial *= i;
}
//
// Lets see how many digits the largest factorial was:
unsigned digits = [Link]().str().size();
//
// Now print them out, using right justification, while we're at it
// we'll indicate the limit of each integer type, so begin by defining
// the limits for 16, 32, 64 etc bit integers:
cpp_int limits[] = {
(cpp_int(1) << 16) - 1,
(cpp_int(1) << 32) - 1,
(cpp_int(1) << 64) - 1,
(cpp_int(1) << 128) - 1,
};
std::string bit_counts[] = { "16", "32", "64", "128" };
unsigned current_limit = 0;
for(unsigned j = 0; j < [Link](); ++j)
{
if(limits[current_limit] < results[j])
{
std::string message = "Limit of " + bit_counts[current_limit] + " bit integers";
std::cout << std::setfill('.') << std::setw(digits+1) << std::right << message << std::set↵
15
1
2
6
24
120
720
5040
40320
................Limit of 16 bit integers
362880
3628800
39916800
479001600
................Limit of 32 bit integers
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
................Limit of 64 bit integers
51090942171709440000
1124000727777607680000
25852016738884976640000
620448401733239439360000
15511210043330985984000000
403291461126605635584000000
10888869450418352160768000000
304888344611713860501504000000
8841761993739701954543616000000
265252859812191058636308480000000
8222838654177922817725562880000000
263130836933693530167218012160000000
8683317618811886495518194401280000000
295232799039604140847618609643520000000
Bit Operations
In this example we'll show how individual bits within an integer may be manipulated, we'll start with an often needed calculation of
2n - 1, which we could obviously implement like this:
using boost::multiprecision::cpp_int;
cpp_int b1(unsigned n)
{
cpp_int r(1);
return (r << n) - 1;
}
16
Calling:
Yields as expected:
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
However, we could equally just set the n'th bit in the result, like this:
cpp_int b2(unsigned n)
{
cpp_int r(0);
return --bit_set(r, n);
}
Note how the bit_set function sets the specified bit in its argument and then returns a reference to the result - which we can then
simply decrement. The result from a call to b2 is the same as that to b1.
We can equally test bits, so for example the n'th bit of the result returned from b2 shouldn't be set unless we increment it first:
assert(!bit_test(b1(200), 200)); // OK
assert(bit_test(++b1(200), 200)); // OK
And of course if we flip the n'th bit after increment, then we should get back to zero:
assert(!bit_flip(++b1(200), 200)); // OK
17
mpfr_float<N> boost/multipreci- 2 GMP and MPFR Very fast and effi- Dependency on
sion/[Link] cient back-end, GNU licensed
with its own stand- GMP and MPFR
ard library imple- libraries.
mentation.
float128 boost/multipreci- 2 Either libquadmath Very fast and effi- Depends on the
sion/[Link] or the Intel C++ cient back-end for compiler being
Math library. 128-bit floating either recent GCC
point values (113- or Intel C++ ver-
bit mantissa, equi- sions.
valent to FOR-
TRAN's QUAD
real)
cpp_bin_float
#include <boost/multiprecision/cpp_bin_float.hpp>
18
enum digit_base_type
{
digit_base_2 = 2,
digit_base_10 = 10
};
template <unsigned Digits, digit_base_type base = digit_base_10, class Allocator = void, class Ex↵
ponent = int, ExponentMin = 0, ExponentMax = 0>
class cpp_bin_float;
}} // namespaces
The cpp_bin_float back-end is used in conjunction with number: It acts as an entirely C++ (header only and dependency free)
floating-point number type that is a drop-in replacement for the native C++ floating-point types, but with much greater precision.
Type cpp_bin_float can be used at fixed precision by specifying a non-zero Digits template parameter. The typedefs
cpp_bin_float_50 and cpp_bin_float_100 provide arithmetic types at 50 and 100 decimal digits precision respectively.
Optionally, you can specify whether the precision is specified in decimal digits or binary bits - for example to declare a
cpp_bin_float with exactly the same precision as double one would use number<cpp_bin_float<53, digit_base_2> >.
The typedefs cpp_bin_float_single, cpp_bin_float_double, cpp_bin_float_quad and cpp_bin_float_double_ex-
tended provide software analogues of the IEEE single, double and quad float data types, plus the Intel-extended-double type respect-
ively. Note that while these types are functionally equivalent to the native IEEE types, but they do not have the same size or bit-
layout as true IEEE compatible types.
Normally cpp_bin_float allocates no memory: all of the space required for its digits are allocated directly within the class. As a
result care should be taken not to use the class with too high a digit count as stack space requirements can grow out of control. If
that represents a problem then providing an allocator as a template parameter causes cpp_bin_float to dynamically allocate the
memory it needs: this significantly reduces the size of cpp_bin_float and increases the viable upper limit on the number of digits
at the expense of performance. However, please bear in mind that arithmetic operations rapidly become very expensive as the digit
count grows: the current implementation really isn't optimized or designed for large digit counts. Note that since the actual type of
the objects allocated is completely opaque, the suggestion would be to use an allocator with void value_type, for example: num-
ber<cpp_bin_float<1000, digit_base_10, std::allocator<void> > >.
The final template parameters determine the type and range of the exponent: parameter Exponent can be any signed integer type,
but note that MinExponent and MaxExponent can not go right up to the limits of the Exponent type as there has to be a little extra
headroom for internal calculations. You will get a compile time error if this is the case. In addition if MinExponent or MaxExponent
are zero, then the library will choose suitable values that are as large as possible given the constraints of the type and need for extra
headroom for internal calculations.
There is full standard library and numeric_limits support available for this type.
• The radix of this type is 2, even when the precision is specified as decimal digits.
19
• 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.
• Any number instantiated on this type, is convertible to any other number instantiated on this type - for example you can convert
from number<cpp_bin_float<50> > to number<cpp_bin_float<SomeOtherValue> >. Narrowing conversions round to
nearest and are explicit.
• Conversion from a string results in a std::runtime_error being thrown if the string can not be interpreted as a valid floating
point number.
• All arithmetic operations are correctly rounded to nearest. String conversions and the sqrt function are also correctly rounded,
but transcendental functions (sin, cos, pow, exp etc) are not.
cpp_bin_float example:
#include <boost/multiprecision/cpp_bin_float.hpp>
cpp_dec_float
#include <boost/multiprecision/cpp_dec_float.hpp>
}} // 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. Op-
tionally, you can specify an integer type to use for the exponent, this defaults to a 32-bit integer type which is more than large enough
for the vast majority of use cases, but larger types such as long long can also be specified if you need a truly huge exponent range.
In any case the ExponentType must be a built in signed integer type at least 2 bytes and 16-bits wide.
20
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.
• 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.
• 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 trun-
cating 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.
cpp_dec_float example:
#include <boost/multiprecision/cpp_dec_float.hpp>
gmp_float
#include <boost/multiprecision/[Link]>
21
}} // 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 numbers 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 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.
• Default constructed gmp_floats 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.
22
GMP example:
#include <boost/multiprecision/[Link]>
mpfr_float
#include <boost/multiprecision/[Link]>
enum mpfr_allocation_type
{
allocate_stack,
allocate_dynamic
};
}} // 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 numbers member functions.
23
In addition the second template parameter lets you choose between dynamic allocation (the default, and uses MPFR's normal alloc-
ation routines), or stack allocation (where all the memory required for the underlying data types is stored within mp-
fr_float_backend). The latter option can result in significantly faster code, at the expense of growing the size of mp-
fr_float_backend. It can only be used at fixed precision, and should only be used for lower digit counts. Note that we can not
guarantee that using allocate_stack won't cause any calls to mpfr's allocation routines, as mpfr may call these inside it's own
code. The following table gives an idea of the performance tradeoff's at 50 decimal digits precision2:
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 number wrappers around those types: number<mpfr_float_backend<M> >, number<mpf_float<M> >, num-
ber<gmp_int>, number<gmp_rational>.
It's also possible to access the underlying mpfr_t via the data() member function of mpfr_float_backend.
• A default constructed mpfr_float_backend is set to a NaN (this is the default MPFR behavior).
• No changes are made to GMP or MPFR global settings, so this type can coexist with existing MPFR or GMP code.
• The code can equally use MPIR in place of GMP - indeed that is the preferred option on Win32.
• This backend supports rvalue-references and is move-aware, making instantiations of number on this backend move aware.
• Conversion from a string results in a std::runtime_error being thrown if the string can not be interpreted as a valid floating
point number.
2
Compiled with VC++10 and /Ox, with MPFR-3.0.0 and MPIR-2.3.0
24
MPFR example:
#include <boost/multiprecision/[Link]>
float128
#include <boost/multiprecision/[Link]>
class float128_backend;
}} // namespaces
The float128 number type is a very thin wrapper around GCC's float128 or Intel's _Quad data types and provides an real-number
type that is a drop-in replacement for the native C++ floating-point types, but with a 113 bit mantissa, and compatible with FORTRAN's
128-bit QUAD real.
All the usual standard library and numeric_limits support are available, performance should be equivalent to the underlying
native types: for example the LINPACK benchmarks for GCC's float128 and boost::multiprecision::float128 both
achieved 5.6 MFLOPS3.
As well as the usual conversions from arithmetic and string types, instances of float128 are copy constructible and assignable
from GCC's float128 and Intel's _Quad data types.
It's also possible to access the underlying float128 or _Quad type via the data() member function of float128_backend.
• This backend supports rvalue-references and is move-aware, making instantiations of number on this backend move aware.
3
On 64-bit Ubuntu 11.10, GCC-4.8.0, Intel Core 2 Duo T5800.
25
• It is not possible to round-trip objects of this type to and from a string and get back exactly the same value when compiled with
Intel's C++ compiler and using _Quad as the underlying type: this is a current limitation of our code. Round tripping when using
float128 as the underlying type is possible (both for GCC and Intel).
• Conversion from a string results in a std::runtime_error being thrown if the string can not be interpreted as a valid floating
point number.
• When using the Intel compiler, the underlying type defaults to float128 if it's available and _Quad if not. You can override the
default by defining either BOOST_MP_USE_FLOAT128 or BOOST_MP_USE_QUAD.
• When the underlying type is Intel's _Quad type, the code must be compiled with the compiler option -Qoption,cpp,--exten-
ded_float_type.
float128 example:
#include <boost/multiprecision/[Link]>
Examples
Area of Circle
Generic numeric programming employs templates to use the same code for different floating-point types and functions. Consider
the area of a circle a of radius r, given by
a = π * r2
The area of a circle can be computed in generic programming using [Link] for the constant π as shown below:
26
#include <boost/math/constants/[Link]>
template<typename T>
inline T area_of_a_circle(T r)
{
using boost::math::constants::pi;
return pi<T>() * r * r;
}
It is possible to use area_of_a_circle() with built-in floating-point types as well as floating-point types from [Link].
In particular, consider a system with 4-byte single-precision float, 8-byte double-precision double and also the cpp_dec_float_50
data type from [Link] with 50 decimal digits of precision.
We can compute and print the approximate area of a circle with radius 123/100 for float, double and cpp_dec_float_50 with
the program below.
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>
using boost::multiprecision::cpp_dec_float_50;
// 4.75292
std::cout
<< std::setprecision(std::numeric_limits<float>::digits10)
<< a_f
<< std::endl;
// 4.752915525616
std::cout
<< std::setprecision(std::numeric_limits<double>::digits10)
<< a_d
<< std::endl;
// 4.7529155256159981904701331745635599135018975843146
std::cout
<< std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10)
<< a_mp
<< std::endl;
}
In the next example we'll look at calling both standard library and [Link] functions from within generic code. We'll also show
how to cope with template arguments which are expression-templates rather than number types.
27
If we were to implement this at double precision using [Link]'s facilities for the Gamma and Bessel function calls it would look
like this:
9.822663964796047e-001
Now let's implement the function again, but this time using the multiprecision type cpp_dec_float_50 as the argument type:
boost::multiprecision::cpp_dec_float_50
JEL2(boost::multiprecision::cpp_dec_float_50 v, boost::multiprecision::cpp_dec_float_50 z)
{
return boost::math::tgamma(v + 1) * boost::math::cyl_bessel_j(v, z) / boost::multipreci↵
sion::pow(z / 2, v);
}
The implementation is almost the same as before, but with one key difference - we can no longer call std::pow, instead we must
call the version inside the boost::multiprecision namespace. In point of fact, we could have omitted the namespace prefix on
the call to pow since the right overload would have been found via argument dependent lookup in any case.
Note also that the first argument to pow along with the argument to tgamma in the above code are actually expression templates.
The pow and tgamma functions will handle these arguments just fine.
Which outputs:
9.82266396479604757017335009796882833995903762577173e-01
Now that we've seen some non-template examples, lets repeat the code again, but this time as a template that can be called either
with a builtin type (float, double etc), or with a multiprecision type:
Once again the code is almost the same as before, but the call to pow has changed yet again. We need the call to resolve to either
std::pow (when the argument is a builtin type), or to boost::multiprecision::pow (when the argument is a multiprecision
28
type). We do that by making the call unqualified so that versions of pow defined in the same namespace as type Float are found
via argument dependent lookup, while the using std::pow directive makes the standard library versions visible for builtin floating
point types.
Let's call the function with both double and multiprecision arguments:
Which outputs:
9.822663964796047e-001
9.82266396479604757017335009796882833995903762577173e-01
Unfortunately there is a problem with this version: if we were to call it like this:
Then we would get a long and inscrutable error message from the compiler: the problem here is that the first argument to JEL3 is
not a number type, but an expression template. We could obviously add a typecast to fix the issue:
However, if we want the function JEL to be truly reusable, then a better solution might be preferred. To achieve this we can borrow
some code from [Link] which calculates the return type of mixed-argument functions, here's how the new code looks now:
As you can see the two arguments to the function are now separate template types, and the return type is computed using the pro-
mote_args metafunction from [Link].
9.8226639647960475701733500979688283399590376257717309069410413822165082248153638454147004236848917775e-
01
As a bonus, we can now call the function not just with expression templates, but with other mixed types as well: for example float
and double or int and double, and the correct return type will be computed in each case.
Note that while in this case we didn't have to change the body of the function, in the general case any function like this which creates
local variables internally would have to use promote_args to work out what type those variables should be, for example:
29
Calculating a Derivative
In this example we'll add even more power to generic numeric programming using not only different floating-point types but also
function objects as template parameters. Consider some well-known central difference rules for numerically computing the first de-
rivative of a function f′(x) with x ∈ ℜ:
f ′( x) ≈ m1 + O(dx2)
4 1 4
(1) f ′( x) ≈ 3 m1 − 3 m2 + O dx ( )
3 3 1 6
f ′( x) ≈ 2 m1 − 5 m2 + 10 m3 + O dx ( )
Where the difference terms mn are given by:
f ( x + dx) − f ( x − dx)
m1 = 2dx
f ( x + 2dx) − f ( x − 2dx)
(2) m2 = 4dx
f ( x + 3dx) − f ( x − 3dx)
m3 = 6dx
The third formula in Equation 1 is a three-point central difference rule. It calculates the first derivative of f′(x) to O(dx6), where dx
is the given step-size. For example, if the step-size is 0.01 this derivative calculation has about 6 decimal digits of precision - just
about right for the 7 decimal digits of single-precision float. Let's make a generic template subroutine using this three-point central
difference rule. In particular:
30
The derivative() template function can be used to compute the first derivative of any function to O(dx6). For example, consider
the first derivative of sin(x) evaluated at x = π/3. In other words,
d
(3) | π 1
dx sinx x= π3 = cos 3 = 2
The code below computes the derivative in Equation 3 for float, double and boost's multiple-precision type cpp_dec_float_50.
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/math/constants/[Link]>
// 5.000029e-001
std::cout
<< std::setprecision(std::numeric_limits<float>::digits10)
<< d_f
<< std::endl;
// 4.999999999998876e-001
std::cout
<< std::setprecision(std::numeric_limits<double>::digits10)
<< d_d
<< std::endl;
31
// 4.99999999999999999999999999999999999999999999999999e-01
std::cout
<< std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10)
<< d_mp
<< std::endl;
}
The expected value of the derivative is 0.5. This central difference rule in this example is ill-conditioned, meaning it suffers from
slight loss of precision. With that in mind, the results agree with the expected value of 0.5.
We can take this a step further and use our derivative function to compute a partial derivative. For example if we take the incomplete
gamma function P(a, z), and take the derivative with respect to z at (2,2) then we can calculate the result as shown below, for good
measure we'll compare with the "correct" result obtained from a call to gamma_p_derivative, the results agree to approximately 44
digits:
cpp_dec_float_50 gd = derivative(
cpp_dec_float_50(2),
cpp_dec_float_50(1.0E-9),
[](const cpp_dec_float_50& x) ->cpp_dec_float_50
{
return boost::math::gamma_p(2, x);
}
);
// 2.70670566473225383787998989944968806815263091819151e-01
std::cout
<< std::setprecision(std::numeric_limits<cpp_dec_float_50>::digits10)
<< gd
<< std::endl;
// 2.70670566473225383787998989944968806815253190143120e-01
std::cout << boost::math::gamma_p_derivat↵
ive(cpp_dec_float_50(2), cpp_dec_float_50(2)) << std::endl;
Calculating an Integral
Similar to the generic derivative example, we can calculate integrals in a similar manner:
32
value_type h = (b - a);
value_type I = (func(a) + func(b)) * (h / 2);
value_type sum(0);
for(unsigned j = 1U; j <= n; j++)
{
sum += func(a + (value_type((j * 2) - 1) * h));
}
const value_type I0 = I;
I = (I / 2) + (h * sum);
n *= 2U;
}
return I;
}
The following sample program shows how the function can be called, we begin by defining a function object, which when integrated
should yield the Bessel J function:
template<typename value_type>
class cyl_bessel_j_integral_rep
{
public:
cyl_bessel_j_integral_rep(const unsigned N,
const value_type& X) : n(N), x(X) { }
private:
const unsigned n;
const value_type x;
};
33
// 0.166369
std::cout
<< std::setprecision(std::numeric_limits<float>::digits10)
<< j2_f
<< std::endl;
// 0.166369383786814
std::cout
<< std::setprecision(std::numeric_limits<double>::digits10)
<< j2_d
<< std::endl;
// 0.16636938378681407351267852431513159437103348245333
std::cout
<< std::setprecision(std::numeric_limits<mp_type>::digits10)
<< j2_mp
<< std::endl;
//
// Print true value for comparison:
// 0.166369383786814073512678524315131594371033482453329
std::cout << boost::math::cyl_bessel_j(2, mp_type(123) / 100) << std::endl;
}
Polynomial Evaluation
In this example we'll look at polynomial evaluation, this is not only an important use case, but it's one that number performs partic-
ularly well at because the expression templates completely eliminate all temporaries from a Horner polynomial evaluation scheme.
The following code evaluates sin(x) as a polynomial, accurate to at least 64 decimal places:
34
using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<64> > mp_type;
35
* x2 + coefs[30U])
* x2 + coefs[29U])
* x2 + coefs[28U])
* x2 + coefs[27U])
* x2 + coefs[26U])
* x2 + coefs[25U])
* x2 + coefs[24U])
* x2 + coefs[23U])
* x2 + coefs[22U])
* x2 + coefs[21U])
* x2 + coefs[20U])
* x2 + coefs[19U])
* x2 + coefs[18U])
* x2 + coefs[17U])
* x2 + coefs[16U])
* x2 + coefs[15U])
* x2 + coefs[14U])
* x2 + coefs[13U])
* x2 + coefs[12U])
* x2 + coefs[11U])
* x2 + coefs[10U])
* x2 + coefs[9U])
* x2 + coefs[8U])
* x2 + coefs[7U])
* x2 + coefs[6U])
* x2 + coefs[5U])
* x2 + coefs[4U])
* x2 + coefs[3U])
* x2 + coefs[2U])
* x2 + coefs[1U])
* x2 + coefs[0U])
* v;
return sum;
}
7.0710678118654752440084436210484903928483593768847403658833986900e-01
mpfi_float
#include <boost/multiprecision/[Link]>
36
}} // namespaces
The mpfi_float_backend type is used in conjunction with number: It acts as a thin wrapper around the MPFI mpfi_t to provide
an real-number type that is a drop-in replacement for the native C++ floating-point types, but with much greater precision and imple-
menting interval arithmetic.
Type mpfi_float_backend can be used at fixed precision by specifying a non-zero Digits10 template parameter, or at variable
precision by setting the template argument to zero. The typedefs mpfi_float_50, mpfi_float_100, mpfi_float_500, mpfi_float_1000
provide arithmetic types at 50, 100, 500 and 1000 decimal digits precision respectively. The typedef mpfi_float provides a variable
precision type whose precision can be controlled via the numbers member functions.
Note
This type only provides numeric_limits support when the precision is fixed at compile time.
As well as the usual conversions from arithmetic and string types, instances of number<mpfi_float_backend<N> > are copy
constructible and assignable from:
• The number wrappers around MPFI or MPFR: number<mpfi_float_backend<M> > and number<mpfr_float<M> >.
• There is a two argument constructor taking two number<mpfr_float<M> > arguments specifying the interval.
It's also possible to access the underlying mpfi_t via the data() member function of mpfi_float_backend.
• A default constructed mpfi_float_backend is set to a NaN (this is the default MPFI behavior).
• No changes are made to GMP or MPFR global settings, so this type can coexist with existing MPFR or GMP code.
• The code can equally use MPIR in place of GMP - indeed that is the preferred option on Win32.
• This backend supports rvalue-references and is move-aware, making instantiations of number on this backend move aware.
• Conversion from a string results in a std::runtime_error being thrown if the string can not be interpreted as a valid floating
point number.
There are some additional non member functions for working on intervals:
37
Returns the interval which is the intersection of the a and b. Returns an unspecified empty interval if there is no such intersection.
38
MPFI example:
#include <boost/multiprecision/[Link]>
39
cpp_rational
#include <boost/multiprecision/cpp_int.hpp>
}} // 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.
40
• Conversion from a string results in a std::runtime_error being thrown if the string can not be interpreted as a valid rational
number.
Example:
#include <boost/multiprecision/cpp_int.hpp>
cpp_rational v = 1;
// Do some arithmetic:
for(unsigned i = 1; i <= 1000; ++i)
v *= i;
v /= 10;
gmp_rational
#include <boost/multiprecision/[Link]>
class gmp_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:
• number<gmp_int>.
There is also a two-argument constructor that accepts a numerator and denominator (both of type number<gmp_int>).
41
It's also possible to access the underlying mpq_t via the data() member function of mpq_rational.
• Default constructed mpq_rationals have the value zero (this is the GMP default behavior).
• 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.
Example:
#include <boost/multiprecision/[Link]>
mpq_rational v = 1;
// Do some arithmetic:
for(unsigned i = 1; i <= 1000; ++i)
v *= i;
v /= 10;
tommath_rational
#include <boost/multiprecision/[Link]>
}} // 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.
42
• Default constructed tom_rationals have the value zero (this the inherited [Link] behavior).
• 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 libtommath's global state, so this type can safely coexist with other libtommath code.
• Performance of this type has been found to be pretty poor - this need further investigation - but it appears that [Link]
needs some improvement in this area.
Example:
#include <boost/multiprecision/[Link]>
tom_rational v = 1;
// Do some arithmetic:
for(unsigned i = 1; i <= 1000; ++i)
v *= i;
v /= 10;
Note that using the library in this way largely negates the effect of the expression templates in number.
rational_adaptor
namespace boost{ namespace multiprecision{
}}
The class template rational_adaptor is a back-end for number which converts any existing integer back-end into a rational-
number back-end.
So for example, given an integer back-end type MyIntegerBackend, the use would be something like:
43
MyRational r = 2;
r /= 3;
MyInt i = numerator(r);
assert(i == 2);
logged_adaptor
#include <boost/multiprecision/logged_adaptor.hpp>
template <Backend>
class logged_adaptor;
}} // namespaces
The logged_adaptor type is used in conjunction with number and some other backend type: it acts as a thin wrapper around some
other backend to class number and logs all the events that take place on that object. Before any number operation takes place, it
calls log_prefix_event with the arguments to the operation (up to 4), plus a string describing the operation. Then after the oper-
ation it calls log_postfix_event with the result of the operation, plus a string describing the operation. Optionally, log_post-
fix_event takes a second result argument: this occurs when the result of the operation is not a number, for example when fpclas-
sify is called, log_postfix_event will be called with result1 being the argument to the function, and result2 being the integer
result of fpclassify.
The default versions of log_prefix_event and log_postfix_event do nothing, it is therefore up to the user to overload these
for the particular backend being observed.
This type provides numeric_limits support whenever the template argument Backend does so.
This type is particularly useful when combined with an interval number type - in this case we can use log_postfix_event to
monitor the error accumulated after each operation. We could either set some kind of trap whenever the accumulated error exceeds
some threshold, or simply print out diagnostic information. Using this technique we can quickly locate the cause of numerical in-
stability in a particular routine. The following example demonstrates this technique in a trivial algorithm that deliberately introduces
cancellation error:
44
#include <boost/multiprecision/[Link]>
#include <boost/multiprecision/logged_adaptor.hpp>
#include <iostream>
#include <iomanip>
//
// Begin by overloading log_postfix_event so we can capture each arithmetic event as it happens:
//
namespace boost{ namespace multiprecision{
}}
int main()
{
using namespace boost::multiprecision;
typedef number<logged_adaptor<mpfi_float_backend<17> > > logged_type;
//
// Test case deliberately introduces cancellation error, relative size of interval
// gradually gets larger after each operation:
//
logged_type a = 1;
a /= 10;
When we examine program output we can clearly see that the diameter of the interval increases after each subtraction:
45
debug_adaptor
#include <boost/multiprecision/debug_adaptor.hpp>
46
template <Backend>
class debug_adaptor;
}} // namespaces
The debug_adaptor type is used in conjunction with number and some other backend type: it acts as a thin wrapper around some
other backend to class number and intercepts all operations on that object storing the result as a string within itself.
This type provides numeric_limits support whenever the template argument Backend does so.
This type is particularly useful when your debugger provides a good view of std::string: when this is the case multiprecision
values can easily be inspected in the debugger by looking at the debug_value member of debug_adaptor. The down side of this
approach is that runtimes are much slower when using this type. Set against that it can make debugging very much easier, certainly
much easier than sprinkling code with printf statements.
When used in conjunction with the Visual C++ debugger visualisers, the value of a multiprecision type that uses this backend is
displayed in the debugger just a builtin value would be, here we're inspecting a value of type number<debug_ad-
aptor<cpp_dec_float<50> > >:
Otherwise you will need to expand out the view and look at the "debug_value" member:
47
It works for all the backend types equally too, here it is inspecting a number<debug_adaptor<gmp_rational> >:
Note
These visualizers have only been tested with VC10, also given the ability of buggy visualizers to crash your Visual
C++ debugger, make sure you back up [Link] file before using these!!
48
The next visualizer provides improved views of cpp_int: small numbers are displayed as actual values, while larger numbers are
displayed as an array of hexadecimal parts, with the most significant part first.
49
There is also a ~raw child member that lets you see the actual members of the class:
The visualizer for cpp_dec_float shows the first few digits of the value in the preview field, and the full array of digits when you
expand the view. As before the ~raw child gives you access to the actual data members:
50
• 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):
• A number can be explicitly constructed from an arithmetic type, even when the conversion is lossy:
• A number can be converted to any built in type, via the convert_to member function:
mpz_int z(2);
int i = [Link] convert_to<int>(); // sets i to 2
51
• 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:
• Any number type will interoperate with the builtin types in arithmetic expressions as long as the conversions are not lossy:
• 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 in-
volved, and explicit if it is:
52
int128_t i128 = 0;
int266_t i256 = i128; // OK implicit widening conversion
i128_t = i256; // Error, no assignment operator found, narrowing conversion is ex↵
plicit
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:
More information on what additional types a backend supports conversions from are given in the tutorial for each backend. The
converting constructor will be implicit if the backend's converting constructor is also implicit, and explicit if the backends converting
constructor is also explicit.
#include <boost/multiprecision/[Link]>
53
#include <boost/multiprecision/[Link]>
#include <boost/multiprecision/[Link]>
//
// Declare our random number generator type, the underlying generator
// is the Mersenne twister mt19937 engine, and 256 bits are generated:
//
typedef independent_bits_engine<mt19937, 256, mpz_int> generator_type;
generator_type gen;
//
// Generate some values:
//
std::cout << std::hex << std::showbase;
for(unsigned i = 0; i < 10; ++i)
std::cout << gen() << std::endl;
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:
#include <boost/multiprecision/[Link]>
#include <boost/multiprecision/[Link]>
//
// Generate integers in a given range using uniform_int,
// the underlying generator is invoked multiple times
// to generate enough bits:
//
mt19937 mt;
uniform_int_distribution<mpz_int> ui(0, mpz_int(1) << 256);
//
// Generate the numbers:
//
std::cout << std::hex << std::showbase;
for(unsigned i = 0; i < 10; ++i)
std::cout << ui(mt) << std::endl;
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):
54
#include <boost/multiprecision/[Link]>
#include <boost/multiprecision/[Link]>
Finally, we can modify the above example to produce numbers distributed according to some distribution:
#include <boost/multiprecision/[Link]>
#include <boost/multiprecision/[Link]>
Primality Testing
The library implements a Miller-Rabin test for primality:
#include <boost/multiprecision/miller_rabin.hpp>
These functions perform a Miller-Rabin test for primality, if the result is false then n is definitely composite, while if the result is
true then n is probably prime. The probability to declare a composite n as probable prime is at most 0.25trials. Note that this does not
allow a statement about the probability of n being actually prime (for that, the prior probability would have to be known). The algorithm
used performs some trial divisions to exclude small prime factors, does one Fermat test to exclude many more composites, and then
55
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 [Link]. 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:
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/miller_rabin.hpp>
#include <iostream>
#include <iomanip>
int main()
{
using namespace boost::random;
using namespace boost::multiprecision;
There is limited support for constexpr and user-defined literals 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
56
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:
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 man↵
agement.
There is also limited support for user defined-literals - these are limited to unchecked, fixed precision cpp_int's which are specified
in hexadecimal notation. The suffixes supported are:
Suffix Meaning
_cppi S p e c i fi e s
a value of type: num-
ber<cpp_int_backend<N,N,signed_magnitude,un-
checked,void> >, where N is chosen to contain just enough
digits to hold the number specified.
_cppiN S p e c i fi e s
a value of type num-
ber<cpp_int_backend<N,N,signed_magnitude,un-
checked,void> >.
_cppuiN S p e c i fi e s
a value of type num-
ber<cpp_int_backend<N,N,signed_magnitude,un-
checked,void> >.
In each case, use of these suffixes with hexadecimal values produces a constexpr result.
Examples:
57
//
// Any use of user defined literals requires that we import the literal-operators
// into current scope first:
using namespace boost::multiprecision::literals;
//
// To keep things simple in the example, we'll make our types used visible to this scope as well:
using namespace boost::multiprecision;
//
// The value zero as a number<cpp_int_backend<4,4,signed_magnitude,unchecked,void> >:
constexpr auto a = 0x0_cppi;
// The type of each constant has 4 bits per hexadecimal digit,
// so this is of type uint256_t (ie number<cpp_int_backend<256,256,unsigned_magnitude,un↵
checked,void> >):
constexpr auto b = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cppui;
//
// Smaller values can be assigned to larger values:
int256_t c = 0x1234_cppi; // OK
//
// However, this does not currently work in constexpr contexts:
constexpr int256_t d = 0x1_cppi; // Compiler error
//
// Constants can be padded out with leading zeros to generate wider types:
constexpr uint256_t e = 0x0000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFF_cp↵
pui; // OK
//
// However, specific width types are best produced with specific-width suffixes,
// ones supported by default are `_cpp[u]i128`, `_cpp[u]i256`, `_cpp[u]i512`, `_cpp[u]i1024`.
//
constexpr int128_t f = 0x1234_cppi128; // OK, always produces an int128_t as the result.
constex↵
pr uint1024_t g = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccc_cp↵
pui1024;
//
// If other specific width types are required, then there is a macro for generating the operators
// for these. The macro can be used at namespace scope only:
//
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(2048);
//
// Now we can create 2048-bit literals as well:
constexpr auto h = 0xff_cppi2048; // h is of type number<cpp_int_backend<2048,2048,signed_mag↵
nitude,unchecked,void> >
//
// Finally negative values are handled via the unary minus operator:
//
constexpr int1024_t i = -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cp↵
pui1024;
//
// Which means this also works:
constexpr int1024_t j = -g; // OK: unary minus operator is constexpr.
The following table summarises the situation for conversions from native types:
58
cpp_int Conversions from integer types are exact if the target has suffi-
cient 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 con-
version 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 con-
version from long double which should be exact provided
the target type has as much precision as a long double.
• Where the operands are of the same precision, but yield a higher precision result.
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);
59
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:
#include <boost/multiprecision/cpp_int.hpp>
boost::uint64_t i = (std::numeric_limits<boost::uint64_t>::max)();
boost::uint64_t j = 1;
uint128_t ui128;
uint256_t ui256;
//
// Start by performing arithmetic on 64-bit integers to yield 128-bit results:
//
std::cout << std::hex << std::showbase << i << std::endl;
std::cout << std::hex << std::showbase << add(ui128, i, j) << std::endl;
std::cout << std::hex << std::showbase << multiply(ui128, i, i) << std::endl;
//
// The try squaring a 128-bit integer to yield a 256-bit result:
//
ui128 = (std::numeric_limits<uint128_t>::max)();
std::cout << std::hex << std::showbase << multiply(ui256, ui128, ui128) << std::endl;
0xffffffffffffffff
0x10000000000000000
0xFFFFFFFFFFFFFFFE0000000000000001
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000000000000000000000000000001
60
Some of these functions are trivial, others use compiler intrinsics (where available) to ensure optimal evaluation.
Returns bp % m.
Sets q = x / y and r = x % y.
Returns x % val;
61
Returns the integer square root s of x and sets r to the remainder x - s2.
The regular Miller-Rabin functions in <boost/multiprecision/miller_rabin.hpp> are defined in terms of the above generic
operations, and so function equally well for built in and multiprecision types.
[Link] Support
Support for serialization comes in two forms:
• Classes number, debug_adaptor, logged_adaptor and rational_adaptor have "pass through" serialization support which requires
the underlying backend to be serializable.
• Backends cpp_int, cpp_bin_float, cpp_dec_float and float128 have full support for [Link].
Numeric Limits
[Link] tries hard to implement std::numeric_limits for all types as far as possible and meaningful because ex-
perience with [Link] has shown that this aids portability.
62
This in turn refers to the C standard SC22/WG11 N507 DRAFT INTERNATIONAL ISO/IEC STANDARD WD 10967-1 Information
technology Language independent arithmetic Part 1: Integer and Floating point arithmetic.
Compiler options, processor type, and definition of macros or assembler instructions to control denormal numbers will alter the
values in the tables given below.
Warning
GMP's mpf_t does not have a concept of overflow: operations that lead to overflow eventually run of out of resources
and terminate with stack overflow (often after several seconds).
std::numeric_limits<> constants
is_specialized
true for all arithmetic types (integer, floating and fixed-point) for which std::numeric_limits<T>::numeric_limits is
specialized.
A typical test is
if (std::numeric_limits<T>::is_specialized == false)
{
std::cout << "type " << typeid(T).name() << " is not specialized for std::numeric_lim↵
its!" << std::endl;
// ...
}
Typically numeric_limits<T>::is_specialized is true for all T where the compile-time constant members of numeric_limits
are indeed known at compile time, and don't vary at runtime. For example floating point types with runtime-variable precision such
as mpfr_float have no numeric_limits specialization as it would be impossible to define all the members at compile time. In
contrast the precision of a type such as mpfr_float_50 is known at compile time, and so it does have a numeric_limits special-
ization.
Note that not all the std::numeric_limits member constants and functions are meaningful for all user-defined types (UDT),
such as the decimal and binary multiprecision types provided here. More information on this is given in the sections below.
infinity
For floating-point types, ∞ is defined wherever possible, but clearly infinity is meaningless for __arbitrary_precision arithmetic
backends, and there is one floating point type (GMP's mpf_t, see gmp_float) which has no notion of infinity or NaN at all.
if(std::numeric_limits<T>::has_infinity)
{
std::cout << std::numeric_limits<T>::infinity() << std::endl;
}
63
If the backend is switched to a type that does not support infinity then, without checks like this, there will be trouble.
is_signed
std::numeric_limits<T>::is_signed == true if the type T is signed.
For built-in binary types, the sign is held in a single bit, but for other types (cpp_dec_float and cpp_bin_float) it may be a separate
storage element, usually bool.
is_exact
std::numeric_limits<T>::is_exact == true if type T uses exact representations.
This is defined as true for all integer types and false for floating-point types.
ISO/IEC 10967-1, Language independent arithmetic, noted by the C++ Standard defines
The important practical distinction is that all integers (up to max()) can be stored exactly.
Floating-point types cannot store all real values (those in the set of ℜ) exactly. For example, 0.5 can be stored exactly in a binary
floating-point, but 0.1 cannot. What is stored is the nearest representable real value, that is, rounded to nearest.
Fixed-point types (usually decimal) are also defined as exact, in that they only store a fixed precision, so half cents or pennies (or
less) cannot be stored. The results of computations are rounded up or down, just like the result of integer division stored as an integer
result.
There are number of proposals to add Decimal Floating Point Support to C++.
Decimal TR.
is_bounded
std::numeric_limits<T>::is_bounded == true if the set of values represented by the type T is finite.
This is true for all built-in integer, fixed and floating-point types, and most multi-precision types.
is_modulo
std::numeric_limits<T>::is_modulo is defined as true if adding two positive values of type T can yield a result less than
either value.
is_modulo == true means that the type does not overflow, but, for example, 'wraps around' to zero, when adding one to the
max() value.
64
The modulo behaviour is sometimes useful, but also can be unexpected, and sometimes undesired, behaviour.
Overflow of signed integers can be especially unexpected, possibly causing change of sign.
[Link] integer type cpp_int is not modulo because as an __arbitrary_precision types, it expands to hold any value
that the machine resources permit.
However fixed precision cpp_int's may be modulo if they are unchecked (i.e. they behave just like built in integers), but not if they
are checked (overflow causes an exception to be raised).
radix
Constant std::numeric_limits<T>::radix returns either 2 (for built-in and binary types) or 10 (for decimal types).
digits
The number of radix digits that be represented without change:
The values include any implicit bit, so for example, for the ubiquious double using 64 bits (IEEE binary64 ), digits == 53, even
though there are only 52 actual bits of the significand stored in the representation. The value of digits reflects the fact that there
is one implicit bit which is always set to 1.
The [Link] binary types do not use an implicit bit, so the digits member reflects exactly how many bits of precision
were requested:
For the most common case of radix == 2, std::numeric_limits<T>::digits is the number of bits in the representation, not
counting any sign bit.
For a decimal integer type, when radix == 10, it is the number of decimal digits.
digits10
Constant std::numeric_limits<T>::digits10 returns the number of decimal digits that can be represented without change
or loss.
This somewhat inscrutable definition means that an unsigned char can hold decimal values 0..99 without loss of precision or
accuracy, usually from truncation.
Had the definition been 3 then that would imply it could hold 0..999, but as we all know, an 8-bit unsigned char can only hold
0..255, and an attempt to store 256 or more will involve loss or change.
For bounded integers, it is thus one less than number of decimal digits you need to display the biggest integer std::numeric_lim-
its<T>::max(). This value can be used to predict the layout width required for
65
std::cout
<< std::setw(std::numeric_limits<short>::digits10 +1 +1) // digits10+1, and +1 for sign.
<< std::showpos << (std::numeric_limits<short>::max)() // +32767
<< std::endl
<< std::setw(std::numeric_limits<short>::digits10 +1 +1)
<< (std::numeric_limits<short>::min)() << std::endl; // -32767
For example, unsigned short is often stored in 16 bits, so the maximum value is 0xFFFF or 65535.
std::cout
<< std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
<< std::showpos << (std::numeric_limits<unsigned short>::max)() // 65535
<< std::endl
<< std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
<< (std::numeric_limits<unsigned short>::min)() << std::endl; // 0
For bounded floating-point types, if we create a double with a value with digits10 (usually 15) decimal digits, 1e15 or
1000000000000000 :
std::[Link](std::numeric_limits<double>::max_digits10);
double d = 1e15;
double dp1 = d+1;
std::cout << d << "\n" << dp1 << std::endl;
// 1000000000000000
// 1000000000000001
std::cout << dp1 - d << std::endl; // 1
and we can increment this value to 1000000000000001 as expected and show the difference too.
std::[Link](std::numeric_limits<double>::max_digits10);
double d = 1e16;
double dp1 = d+1;
std::cout << d << "\n" << dp1 << std::endl;
// 10000000000000000
// 10000000000000000
std::cout << dp1 - d << std::endl; // 0 !!!
then we find that when we add one it has no effect, and display show that there is loss of precision. See Loss of significance or can-
cellation error.
• If a decimal string with at most digits10( == 15) significant decimal digits is converted to double and then converted back to
the same number of significant decimal digits, then the final string will match the original 15 decimal digit string.
• If a double floating-point number is converted to a decimal string with at least 17 decimal digits and then converted back to
double, then the result will be binary identical to the original double value.
For most purposes, you will much more likely want std::numeric_limits<>::max_digits10, the number of decimal digits
that ensure that a change of one least significant bit (ULP) produces a different decimal digits string.
For nearly all floating-point types, max_digits10 is digits10+2, but you should use max_digits10 where possible.
If max_digits10 is not available, you should using the Kahan formula for floating-point type T
66
The factor is log10(2) = 0.3010 but must be evaluated at compile time using only integers.
(See also Richard P. Brent and Paul Zimmerman, Modern Computer Arithmetic Equation 3.8 on page 116.).
The extra two (or 3) least significant digits are 'noisy' and may be junk, but if you want to 'round-trip' - printing a value out and
reading it back in - you must use [Link](std::numeric_limits<T>::max_digits10). For at least one popular compiler,
you must also use std::scientific format.
max_digits10
std::numeric_limits<T>::max_digits10 was added for floating-point because digits10 decimal digits are insufficient to
show a least significant bit (ULP) change giving puzzling displays like
0.666666666666667 != 0.666666666666667
double write = 2./3; // Any arbitrary value that cannot be represented exactly.
double read = 0;
std::stringstream s;
[Link](std::numeric_limits<double>::digits10); // or `float64_t` for 64-bit IEE754 double.
s << write;
s >> read;
if(read != write)
{
std::cout << std::setprecision(std::numeric_limits<double>::digits10)
<< read << " != " << write << std::endl;
}
If you wish to ensure that a change of one least significant bit (ULP) produces a different decimal digits string, then max_digits10
is the precision to use.
For example:
double pi = boost::math::double_constants::pi;
std::[Link](std::numeric_limits<double>::max_digits10);
std::cout << pi << std::endl; // 3.1415926535897931
using boost::multiprecision::cpp_dec_float_50;
cpp_dec_float_50 pi = boost::math::constants::pi<cpp_dec_float_50>();
std::[Link](std::numeric_limits<cpp_dec_float_50>::max_digits10);
std::cout << pi << std::endl;
// 3.141592653589793238462643383279502884197169399375105820974944592307816406
For integer types, max_digits10 is implementation-dependant, but is usually digits10 + 2. This is the output field width required
for the maximum value of the type T std::numeric_limits<T>::max() including a sign and a space.
67
Note
For Microsoft Visual Studio 2010, std::numeric_limits<float>::max_digits10 is wrongly defined as 8.
It should be 9.
Note
For Microsoft Visual Studio, and default float format, a small range of values approximately 0.0001 to 0.004, with
exponent values of 3f2 to 3f6, are wrongly input by one least significant bit, probably every third value of significand.
Note
BOOST_NO_CXX11_NUMERIC_LIMITS is a suitable feature-test macro to determine if std::numeric_lim-
its<float>::max_digits10 is implemented on any platform. If max_digits10 is not available, you should
using the Kahan formula for floating-point type T. See above.
#if defined(BOOST_NO_CXX11_NUMERIC_LIMITS)
std::[Link](2 + std::numeric_limits<T>::digits * 3010U/10000U);
#else
# if (_MSC_VER <= 1600) // Correct wrong value for float.
std::[Link](2 + std::numeric_limits<T>::digits * 3010U/10000U);
# else
std::[Link](std::numeric_limits<T>::max_digits10);
# endif
#endif
double x = 1.2345678901234567889;
std::[Link] = 9
x = 1.23456789
round_style
The rounding style determines how the result of floating-point operations is treated when the result cannot be exactly represented
in the significand. Various rounding modes may be provided:
68
std::numeric_limits<T>::round_style == std::round_to_zero;
A decimal type, cpp_dec_float rounds in no particular direction, which is to say it doesn't round at all. And since there are several
guard digits, it's not really the same as truncation (round toward zero) either.
std::numeric_limits<T>::round_style == std::round_to_nearest;
See function std::numeric_limits<T>::round_error for the maximum error (in ULP) that rounding can cause.
has_denorm_loss
true if a loss of precision is detected as a denormalization loss, rather than an inexact result.
denorm_style
Denormalized values are representations with a variable number of exponent bits that can permit gradual underflow, so that, if type
T is double.
• std::denorm_absent, if it does not allow denormalized values. (Always used for all integer and exact types).
true if a type can determine that a value is too small to be represent as a normalized value before rounding it.
Generally true for is_iec559 floating-point built-in types, but false for integer types.
Standard-compliant IEEE 754 floating-point implementations may detect the floating-point underflow at three predefined moments:
1. After computation of a result with absolute value smaller than std::numeric_limits<T>::min(), such implementation detects
tinyness before rounding (e.g. UltraSparc).
2. After rounding of the result to std::numeric_limits<T>::digits bits, if the result is tiny, such implementation detects
tinyness after rounding (e.g. SuperSparc).
69
3. If the conversion of the rounded tiny result to subnormal form resulted in the loss of precision, such implementation detects denorm
loss.
std::numeric_limits<> functions
max function
Function std::numeric_limits<T>::max() returns the largest finite value that can be represented by the type T. If there is no
such value (and numeric_limits<T>::bounded is false) then returns T().
For built-in types there is usually a corresponding MACRO value TYPE_MAX, where TYPE is CHAR, INT, FLOAT etc.
Other types, including those provided by a typedef, for example INT64_T_MAX for int64_t, may provide a macro definition.
To cater for situations where no numeric_limits specialization is available (for example because the precision of the type varies
at runtime), packaged versions of this (and other functions) are provided using
#include <boost/math/tools/[Link]>
T = boost::math::tools::max_value<T>();
Of course, these simply use std::numeric_limits<T>::max() if available, but otherwise 'do something sensible'.
lowest function
Since C++11: std::numeric_limits<T>::lowest() is
-(std::numeric_limits<double>::max)() == std::numeric_limits<double>::lowest();
min function
Function std::numeric_limits<T>::min() returns the minimum finite value that can be represented by the type T.
For built-in types there is usually a corresponding MACRO value TYPE_MIN, where TYPE is CHAR, INT, FLOAT etc.
Other types, including those provided by a typedef, for example INT64_T_MIN for int64_t, may provide a macro definition.
For floating-point types, it is more fully defined as the minimum positive normalized value.
std::numeric_limits<T>::has_denorm == std::denorm_present
To cater for situations where no numeric_limits specialization is available (for example because the precision of the type varies
at runtime), packaged versions of this (and other functions) are provided using
#include <boost/math/tools/[Link]>
T = boost::math::tools::min_value<T>();
70
denorm_min function
Function std::numeric_limits<T>::denorm_min() returns the smallest denormalized value, provided
std::numeric_limits<T>::has_denorm == std::denorm_present
std::[Link](std::numeric_limits<double>::max_digits10);
if (std::numeric_limits<double>::has_denorm == std::denorm_present)
{
double d = std::numeric_limits<double>::denorm_min();
int exponent;
The exponent is effectively reduced from -308 to -324 (though it remains encoded as zero and leading zeros appear in the significand,
thereby losing precision until the significand reaches zero).
round_error
Function std::numeric_limits<T>::round_error() returns the maximum error (in units of ULP) that can be caused by any
basic arithmetic operation.
round_style == std::round_indeterminate;
For floating-point types, when rounding is to nearest, only half a bit is lost by rounding, and round_error == 0.5. In contrast
when rounding is towards zero, or plus/minus infinity, we can loose up to one bit from rounding, and round_error == 1.
For integer types, rounding always to zero, so at worst almost one bit can be rounded, so round_error == 1.
round_error() can be used with std::numeric_limits<T>::epsilon() to estimate the maximum potential error caused by
rounding. For typical floating-point types, round_error() = 1/2, so half epsilon is the maximum potential error.
There are, of course, many occasions when much bigger loss of precision occurs, for example, caused by Loss of significance or
cancellation error or very many iterations.
epsilon
Function std::numeric_limits<T>::epsilon() is meaningful only for non-integral types.
It returns the difference between 1.0 and the next value representable by the floating-point type T. So it is a one least-significant-
bit change in this floating-point value.
71
For double (float_64t) it is 2.2204460492503131e-016 showing all possibly significant 17 decimal digits.
std::[Link](std::numeric_limits<double>::max_digits10);
double d = 1.;
double eps = std::numeric_limits<double>::epsilon();
double dpeps = d+eps;
std::cout << std::showpoint // Ensure all trailing zeros are shown.
<< d << "\n" // 1.0000000000000000
<< dpeps << std::endl; // 2.2204460492503131e-016
std::cout << dpeps - d // 1.0000000000000002
<< std::endl;
We can explicitly increment by one bit using the function boost::math::float_next() and the result is the same as adding
epsilon.
Adding any smaller value, like half epsilon, will have no effect on this value.
std::[Link](std::numeric_limits<double>::max_digits10);
double d = 1.;
double eps = std::numeric_limits<double>::epsilon();
double dpeps = d + eps/2;
So this cancellation error leaves the values equal, despite adding half epsilon.
To achieve greater portability over platform and floating-point type, [Link] and [Link] provide a package of
functions that 'do something sensible' if the standard numeric_limits is not available. To use these #include
<boost/math/tools/[Link]>.
epsilon is very useful to compute a tolerance when comparing floating-point values, a much more difficult task than is commonly
imagined.
For more information you probably want (but still need) see What Every Computer Scientist Should Know About Floating-Point
Arithmetic
The naive test comparing the absolute difference between two values and a tolerance does not give useful results if the values are
too large or too small.
So [Link] uses an algorithm first devised by Knuth for reliably checking if floating-point values are close enough.
See Donald. E. Knuth. The art of computer programming (vol II). Copyright 1998 Addison-Wesley Longman, Inc., 0-201-89684-2.
Addison-Wesley Professional; 3rd edition.
72
See also:
floating-point comparison.
For example, if we want a tolerance that might suit about 9 arithmetical operations, say sqrt(9) = 3, we could define:
T tolerance = 3 * std::numeric_limits<T>::epsilon();
This is very widely used in [Link] testing with [Link]'s macro BOOST_CHECK_CLOSE_FRACTION
T expected = 1.0;
T calculated = 1.0 + std::numeric_limits<T>::epsilon();
used thus:
using boost::multiprecision::number;
using boost::multiprecision::cpp_dec_float;
using boost::multiprecision::et_off;
Note
that [Link] does not yet allow floating-point comparisons with expression templates on, so the default expression
template parameter has been replaced by et_off.
The 'representation' is a particular bit pattern reserved for infinity. For IEEE754 system (for which std::numeric_lim-
its<T>::is_iec559 == true) positive and negative infinity are assigned bit patterns for all defined floating-point types.
Confusingly, the string resulting from outputting this representation, is also implementation-defined. And the string that can be input
to generate the representation is also implementation-defined.
For example, the output is 1.#INF on Microsoft systems, but inf on most *nix platforms.
73
This implementation-defined-ness has hampered use of infinity (and NaNs) but [Link] and [Link] work hard to
provide a sensible representation for all floating-point types, not just the built-in types, which with the use of suitable facets to define
the input and output strings, makes it possible to use these useful features portably and including [Link].
Not-A-Number NaN
Quiet_NaN
For floating-point types only, for which std::numeric_limits<T>::has_quiet_NaN == true, function std::numeric_lim-
its<T>::quiet_NaN() provides an implementation-defined representation for NaN.
NaNs are values to indicate that the result of an assignment or computation is meaningless. A typical example is 0/0 but there are
many others.
NaNs may also be used, to represent missing values: for example, these could, by convention, be ignored in calculations of statistics
like means.
Many of the problems with a representation for Not-A-Number has hampered portable use, similar to those with infinity.
using boost::multiprecision::cpp_bin_float_quad;
if (std::numeric_limits<cpp_bin_float_quad>::has_quiet_NaN == true)
{
cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon();
But using [Link] and suitable facets can permit portable use of both NaNs and positive and negative infinity.
#include <boost/math/special_functions/nonfinite_num_facets.hpp>
74
using boost::multiprecision::cpp_bin_float_quad;
typedef cpp_bin_float_quad T;
using boost::math::nonfinite_num_put;
using boost::math::nonfinite_num_get;
{
std::locale old_locale;
std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
std::stringstream ss;
[Link](new_locale);
T inf = std::numeric_limits<T>::infinity();
ss << inf; // Write out.
assert([Link]() == "inf");
T r;
ss >> r; // Read back in.
assert(inf == r); // Confirms that the floating-point values really are identical.
std::cout << "infinity output was " << [Link]() << std::endl;
std::cout << "infinity input was " << r << std::endl;
}
Similarly we can do the same with NaN (except that we cannot use assert)
{
std::locale old_locale;
std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
std::stringstream ss;
[Link](new_locale);
T n;
T NaN = std::numeric_limits<T>::quiet_NaN();
ss << NaN; // Write out.
assert([Link]() == "nan");
std::cout << "NaN output was " << [Link]() << std::endl;
ss >> n; // Read back in.
std::cout << "NaN input was " << n << std::endl;
}
Signaling NaN
For floating-point types only, for which std::numeric_limits<T>::has_signaling_NaN == true, function std::numer-
ic_limits<T>::signaling_NaN() provides an implementation-defined representation for NaN that causes a hardware trap. It
should be noted however, that at least one implementation of this function causes a hardware trap to be triggered simply by calling
std::numeric_limits<T>::signaling_NaN(), and not only by using the value returned.
75
Program:
numeric_limits_qbk.cpp
Mon Nov 4 18:09:06 2013
BuildInfo:
Platform Win32
Compiler Microsoft Visual C++ version 10.0
MSVC version 160040219.
STL Dinkumware standard library version 520
Boost version 1.55.0
76
77
bool 1 0
char16_t 65535 0
char32_t 4294967295 0
78
type round radix digits digits10 max_di- min_exp min_exp10 max_exp max_exp10 tiny trap
gits10
Integer Types
For an integer type T, all of the following conditions hold:
79
std::numeric_limits<T>::is_specialized == true
std::numeric_limits<T>::is_integer == true
std::numeric_limits<T>::is_exact == true
std::numeric_limits<T>::min_exponent == 0
std::numeric_limits<T>::max_exponent == 0
std::numeric_limits<T>::min_exponent10 == 0
std::numeric_limits<T>::max_exponent10 == 0
std::numeric_limits<T>::is_signed == true
std::numeric_limits<T>::is_bounded == false
Otherwise the type is bounded, and returns a non zero value from:
std::numeric_limits<T>::max()
and has:
std::numeric_limits<T>::is_modulo == true
Rational Types
Rational types are just like integers except that:
std::numeric_limits<T>::is_integer == false
std::numeric_limits<T>::is_exact == false
This is because these types are in essence a rational type with a fixed denominator.
std::numeric_limits<T>::is_specialized == true
std::numeric_limits<T>::is_integer == false
std::numeric_limits<T>::is_exact == false
std::numeric_limits<T>::min_exponent != 0
std::numeric_limits<T>::max_exponent != 0
std::numeric_limits<T>::min_exponent10 != 0
std::numeric_limits<T>::max_exponent10 != 0
80
std::numeric_limits<T>::is_signed == true
And the type may be decimal or binary depending on the value of:
std::numeric_limits<T>::radix
In general, there are no arbitrary precision floating point types, and so:
std::numeric_limits<T>::is_bounded == false
std::numeric_limits<T>::is_exact == true
Complex Numbers
For historical reasons, complex numbers do not specialize std::numeric_limits, instead you must inspect std::numeric_lim-
its<T::value_type>.
Input Output
Loopback testing
Loopback or round-tripping refers to writing out a value as a decimal digit string using std::iostream, usually to a
std::stringstream, and then reading the string back in to another value, and confirming that the two values are identical. A
trivial example using float is:
and this can be run in a loop for all possible values of a 32-bit float. For other floating-point types T, including built-in double, it
takes far too long to test all values, so a reasonable test strategy is to use a large number of random values.
81
T write;
std::stringstream ss;
[Link](std::numeric_limits<T>::max_digits10); // Ensure all potentially significant bits ↵
are output.
[Link](f); // Changed from default iostream format flags if desired.
ss << write; // Output to stringstream.
T read;
ss >> read; // Get read using operator>> from stringstream.
BOOST_CHECK_EQUAL(read, write);
read = static_cast<T>([Link]()); // Get read by converting from decimal digits string represent↵
ation of write.
BOOST_CHECK_EQUAL(read, write);
read = static_cast<T>([Link](0, f)); // Get read using format specified when written.
BOOST_CHECK_EQUAL(read, write);
The test at test_cpp_bin_float_io.cpp allows any floating-point type to be round_tripped using a wide range of fairly random values.
It also includes tests compared a collection of stringdata test cases in a file.
which has the same number of significant bits (53) as 64-bit double precision floating-point.
However, although most outputs are identical, there are differences on some platforms caused by the implementation-dependent
behaviours allowed by the C99 specification C99 ISO/IEC 9899:TC2, incorporated by C++.
"For e, E, f, F, g, and G conversions, if the number of significant decimal digits is at most DECIMAL_DIG, then
the result should be correctly rounded. If the number of significant decimal digits is more than DECIMAL_DIG
but the source value is exactly representable with DECIMAL_DIG digits, then the result should be an exact rep-
resentation with trailing zeros. Otherwise, the source value is bounded by two adjacent decimal strings L < U,
both having DECIMAL_DIG significant digits; the value of the resultant decimal string D should satisfy L<= D
<= U, with the extra stipulation that the error should have a correct sign for the current rounding direction."
So not only is correct rounding for the full number of digits not required, but even if the optional recommended practice is followed,
then the value of these last few digits is unspecified as long as the value is within certain bounds.
Note
Do not expect the output from different platforms to be identical, but cpp_dec_float, cpp_bin_float (and
other backends) outputs should be correctly rounded to the number of digits requested by the set precision and
format.
Macro BOOST_MP_MIN_EXPONENT_DIGITS
C99 Standard for format specifiers, 7.19.6 Formatted input/output functions requires:
"The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent."
#define BOOST_MP_MIN_EXPONENT_DIGITS 2
82
Confusingly, Microsoft (and MinGW) do not conform to this standard and provide at least three digits, for example 1e+001. So
if you want the output to match that from built-in floating-point types on compilers that use Microsofts runtime then use:
#define BOOST_MP_MIN_EXPONENT_DIGITS 3
#define BOOST_MP_MIN_EXPONENT_DIGITS 1
producing a compact output like 2e+4, useful when conserving space is important.
Larger values are also supported, for example, value 4 for 2e+0004 which may be useful to ensure that columns line up.
83
Reference
number
Synopsis
// 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);
84
// 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);
85
// 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;
86
}} // namespaces
}} // namespaces
// numeric_limits support:
namespace std{
Description
This enumerated type is used to specify whether expression templates are turned on (et_on) or turned off (et_off).
This traits class specifies the default expression template option to be used with a particular Backend type. It defaults to et_on.
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_tem-
87
plate_default whose member value defaults to et_on unless the traits class is specialized for a
particular backend.
number();
number(see-below);
number& operator=(see-below);
number& assign(see-below);
Type number is default constructible, and both copy constructible and assignable from:
• Itself.
• Any builtin arithmetic type, as long as the result would not be lossy (for example float to integer conversion).
• 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.
• 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 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;
In addition, if the type has multiple components (for example rational or complex number types), then there is a two argument con-
structor:
number(arg1, arg2);
Where the two args must either be arithmetic types, or types that are convertible to the two components of this.
88
• 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 ?:.
bool is_zero()const;
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.
Returns the number formatted as a string, with at least precision digits, and in scientific format if scientific is true.
89
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.
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.
Returns:
Backend& backend();
const Backend& backend()const;
90
Non-member operators
The arguments to these functions must contain at least one of the following:
• A number.
• Any type for which number has an implicit constructor - for example a builtin arithmetic type.
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).
swap
Swaps a and b.
Iostream Support
91
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.
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.
92
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 determined by the backend implementation. For example the precision of these functions
when used with mpfr_float is determined entirely by MPFR. When these functions use our own implementations, the accuracy of
the transcendental functions is generally a few epsilon. Note however, that the trigonometrical functions incur the usual accuracy
loss when reducing arguments by large multiples of π. Also note that both gmp_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):
93
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.
A traits class that inherits from mpl::int_<N> where N is one of the enumerated values number_kind_integer, num-
ber_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.
A traits class that inherits from mpl::true_ if T is an instance of number<>, otherwise from mpl::false_.
A traits class that inherits from mpl::true_ if T is an expression template type derived from number<>, otherwise from
mpl::false_.
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/[Link]>. Further, when used with fixed precision types (whether built in integers or multipre-
cision 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.
Returns bp 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.
94
Returns bp mod m as an expression template. Fixed precision types are promoted internally to ensure accuracy.
Returns the largest integer x such that x * x < a, and sets the remainder r such that r = a - x * x.
Divides x by y and returns both the quotient and remainder. After the call q = x / y and r = x % y.
Returns the (zero-based) index of the least significant bit that is set to 1.
95
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 in-
ternally to ensure accuracy.
These functions return the numerator and denominator of a rational number respectively.
}} // namespaces
Other [Link] functions and templates may also be specialized or overloaded to ensure interoperability.
std::numeric_limits support
namespace std{
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).
96
cpp_int
namespace boost{ namespace multiprecision{
97
}} // namespaces
Class template cpp_int_backend fulfils all of the requirements for a Backend type. Its members and non-member functions are
deliberately not documented: these are considered implementation details that are subject to change.
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 per-
formed: 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 arbitrary precision types this parameter must
be signed_magnitude. For fixed precision types then this type may be either signed_magnitude or un-
signed_magnitude.
Checked This parameter has two values: checked or unchecked. See the tutorial for more information.
Allocator The allocator to use for dynamic memory allocation, or type void if MaxBits == MinBits.
gmp_int
namespace boost{ namespace multiprecision{
class gmp_int;
}} // namespaces
Class template gmp_int fulfils all of the requirements for a Backend type. Its members and non-member functions are deliberately
not documented: these are considered implementation details that are subject to change.
98
tom_int
namespace boost{ namespace multiprecision{
class tommath_int;
}} // namespaces
Class template tommath_int fulfils all of the requirements for a Backend type. Its members and non-member functions are delib-
erately not documented: these are considered implementation details that are subject to change.
gmp_float
namespace boost{ namespace multiprecision{
}} // namespaces
Class template gmp_float fulfils all of the requirements for a 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_floats of dif-
fering precision.
99
mpfr_float_backend
namespace boost{ namespace multiprecision{
}} // namespaces
Class template mpfr_float_backend fulfils all of the requirements for a 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_backends of differing precision.
cpp_bin_float
namespace boost{ namespace multiprecision{
enum digit_base_type
{
digit_base_2 = 2,
digit_base_10 = 10
};
template <unsigned Digits, digit_base_type base = digit_base_10, class Allocator = void, class Ex↵
ponent = int, ExponentMin = 0, ExponentMax = 0>
class cpp_bin_float;
}} // namespaces
Class template cpp_bin_float fulfils all of the requirements for a Backend type. Its members and non-member functions are de-
liberately not documented: these are considered implementation details that are subject to change.
100
Digits The number of digits precision the type should support. This is normally expressed as base-10 digits, but that can
be changed via the second template parameter.
base An enumerated value (either digit_base_10 or digit_base_2) that indicates whether Digits is base-10 or
base-2
Allocator The allocator used: defaults to type void, meaning all storage is within the class, and no dynamic allocation is
performed, but can be set to a standard library allocator if dynamic allocation makes more sense.
Exponent A signed integer type to use as the type of the exponent - defaults to int.
ExponentMin The smallest (most negative) permitted exponent, defaults to zero, meaning "define as small as possible given
the limitations of the type and our internal requirements".
ExponentMax The largest (most positive) permitted exponent, defaults to zero, meaning "define as large as possible given the
limitations of the type and our internal requirements".
Implementation Notes
Internally, an N-bit cpp_bin_float is represented as an N-bit unsigned integer along with an exponent and a sign. The integer part
is normalized so that it's most significant bit is always 1. The decimal point is assumed to be directly after the most significant bit
of the integer part. The special values zero, infinity and NaN all have the integer part set to zero, and the exponent to one of 3 special
values above the maximum permitted exponent.
Multiplication is trivial: multiply the two N-bit integer mantissa's to obtain a 2N-bit number, then round and adjust the sign and ex-
ponent.
Addition and subtraction proceed similarly - if the exponents are such that there is overlap between the two values, then left shift
the larger value to produce a number with between N and 2N bits, then perform integer addition or subtraction, round, and adjust
the exponent.
Division proceeds as follows: first scale the numerator by some power of 2 so that integer division will produce either an N-bit or
N+1 bit result plus a remainder. If we get an N bit result then the size of twice the remainder compared to the denominator gives us
the rounding direction. Otherwise we have one extra bit in the result which we can use to determine rounding (in this case ties occur
only if the remainder is zero and the extra bit is a 1).
Decimal string to binary conversion proceeds as follows: first parse the digits to produce an integer multiplied by a decimal exponent.
Note that we stop parsing digits once we have parsed as many as can possibly effect the result - this stops the integer part growing
too large when there are a very large number of input digits provided. At this stage if the decimal exponent is positive then the result
is an integer and we can in principle simply multiply by 10^N to get an exact integer result. In practice however, that could produce
some very large integers. We also need to be able to divide by 10^N in the event that the exponent is negative. Therefore calculation
of the 10^N values plus the multiplication or division are performed using limited precision integer arithmetic, plus an exponent,
and a track of the accumulated error. At the end of the calculation we will either be able to round unambiguously, or the error will
be such that we can't tell which way to round. In the latter case we simply up the precision and try again until we have an unambiguously
rounded result.
Binary to decimal conversion proceeds very similarly to the above, our aim is to calculate mantissa * 2^shift * 10^E where
E is the decimal exponent and shift is calculated so that the result is an N bit integer assuming we want N digits printed in the
result. As before we use limited precision arithmetic to calculate the result and up the precision as necessary until the result is unam-
biguously correctly rounded. In addition our initial calculation of the decimal exponent may be out by 1, so we have to correct that
and loop as well in the that case.
101
cpp_dec_float
namespace boost{ namespace multiprecision{
}} // namespaces
Class template cpp_dec_float fulfils all of the requirements for a Backend type. Its members and non-member functions are de-
liberately not documented: these are considered implementation details that are subject to change.
Digits10 The number of decimal digits precision the type should support. Note that this type does not normally perform
any dynamic memory allocation, and as a result the Digits10 template argument should not be set too high or
the class's size will grow unreasonably large.
ExponentType A signed integer type that represents the exponent of the number
Allocator The allocator used: defaults to type void, meaning all storage is within the class, and no dynamic allocation is
performed, but can be set to a standard library allocator if dynamic allocation makes more sense.
}}}
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_con-
vertible<From, To>::type, and will need to be specialised for Backends that have constructors marked as explicit.
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.
102
Member value is true if From is only explicitly convertible to To and not implicitly convertible, or if is_lossy_conver-
sion<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.
These two traits inherit from either mpl::true_ or mpl::false_, by default types are assumed to be signed unless is_un-
signed_number is specialized for that type.
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, ss is variable of type
std::streamsize and ff is a variable of type std::ios_base::fmtflags.
103
104
105
eval_frexp(b, cb, pi) void Stores values in b and *pi std::runtime_error if the
such that the value of cb is b exponent of cb is too large to
* 2*pi, only required when B is be stored in an int.
a floating-point type.
106
107
108
Comparisons:
109
110
Basic arithmetic:
111
112
113
114
115
116
117
118
119
120
121
Sign manipulation:
122
123
124
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.
125
Header Contains
126
Header Contains
127
Performance Comparison
The Overhead in the Number Class Wrapper
Using a simple 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:
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
voronoi-diagram builder test:
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
libtommath-0.42.0. The tests were run on 32-bit Windows Vista machine.
128
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations turned on (/Ox), and used MPIR-2.3.0 and MP-
FR-3.0.0. The tests were run on 32-bit Windows Vista machine.
129
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 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:
cpp_int 5.25827(0.379597s)
int1024_t 4.37589(0.315897s)
checked_int1024_t 4.52396(0.326587s)
mpz_int 1(0.0721905s)
tom_int 2.60673(0.188181s)
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
130
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 MP-
FR-3.0.0. The tests were run on 32-bit Windows Vista machine.
131
132
133
134
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations turned on (/Ox), and used MPIR-2.3.0 and MP-
FR-3.0.0. The tests were run on 32-bit Windows Vista machine.
135
136
137
138
139
140
141
142
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations turned on (/Ox), and used MPIR-2.3.0 and MP-
FR-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.
143
144
145
Test code was compiled with Microsoft Visual Studio 2010 with all optimisations turned on (/Ox), and used MPIR-2.3.0 and MP-
FR-3.0.0. The tests were run on 32-bit Windows Vista machine.
146
Roadmap
History
Multiprecision-2.2.2 (Boost-1.56)
• Change floating point to rational conversions to be implicit, see 10082.
Multiprecision-2.2.1
• Fix bug in assignment from string in cpp_int, see 9936.
Multiprecision-2.2.0
• Moved to [Link] specific version number - we have one breaking change in Boost-1.54 which makes this major
version 2, plus two releases with new features since then.
• Fixed gmp_rational to allow move-copy from an already copied-from object, see 9497.
Boost-1.55
• Added support for [Link].
• Fixed bug in fixed precision cpp_int IO code that causes conversion to string to fail when the bit count is very small (less than
CHAR_BIT). See 8745.
• Fixed bug in cpp_int that causes left shift to fail when a fixed precision type would overflow. See 8741.
• Fixed calls to functions which are required to be macros in C99. See 8732.
• Fixed bug that causes construction from INT_MIN, LONG_MIN etc to fail in cpp_int. See 8711.
1.54
• Breaking change renamed rational_adapter to rational_adaptor.
• Add logged_adaptor.
• Add support for 128-bit floats via GCC's float128 or Intel's _Quad data types.
147
• Fixed bug in integer division of cpp_int that results in incorrect sign of cpp_int when both arguments are small enough to fit
in a double_limb_type. See 8126.
• Fixed bug in subtraction of a single limb in cpp_int that results in incorrect value when the result should have a 0 in the last
limb: 8133.
• Fixed bug in cpp_int where division of 0 by something doesn't get zero in the result: 8160.
• Fixed bug in some transcendental functions that caused incorrect return values when variables are reused, for example with a =
pow(a, b). See 8326.
• Fixed some assignment operations in the mpfr and gmp backends to be safe if the target has been moved from: 8667.
• Fixed bug in cpp_int that gives incorrect answer for 0%N for large N: 8670.
• Fixed set_precision in mpfr backend so it doesn't trample over an existing value: 8692.
1.53
• First Release.
• 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.
• 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 section on mixed precision arithmetic, and added support for operations yielding a higher precision result than either of
the arguments.
Pre-review history
• 2011-2012, John Maddock adds an expression template enabled front end to Christopher's code, and adds support for other
backends.
148
• 2011, Christopher Kormanyos publishes the decimal floating point code under the Boost Software Licence. The code is published
as: "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.
TODO
More a list of what could be done, rather than what should be done (which may be a much smaller list!).
• Can ring types (exact floating point types) be supported? The answer should be yes, but someone needs to write it, the hard part
is IO and binary-decimal conversion.
• A 2's complement fixed precision int that uses exactly N bits and no more.
• Should we provide min/max overloads for expression templates? (Not done - we can't overload functions declared in the std
namespace :-( ).
• Document why we don't abstract out addition/multiplication algorithms etc. (done - FAQ)
• 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).
• 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 implement-
ation detail, and "optional" requirements are optimisations which can't be detected by the user). Not done: this is an implementation
detail, the exact list of requirements satisfied is purely an optimization, not something the user can detect.
149
• IIUC convert_to is used to emulate in c++98 compilers C++11 explicit conversions. Could the explicit conversion operator be
added on compilers supporting it? (Done 2012/09/15).
• The front-end should make the differences between implicit and explicit construction (Done 2012/09/15).
• The tutorial should add more examples concerning implicit or explicit conversions. (Done 2012/09/15).
• The documentation must explain how move semantics helps in this domain and what the backend needs to do to profit from this
optimization. (Done 2012/09/15).
• The documentation should contain Throws specification on the mp_number and backend requirements operations. (Done 2012/09/15).
• The library interface should use the noexcept (BOOST_NOEXCEPT, ...) facilities (Done 2012/09/15).
• It is unfortunate that the generic mp_number front end can not make use constexpr as not all the backends can ensure this (done
- we can go quite a way).
• literals: The library doesn't provide some kind of literals. I think that the mp_number class should provide a way to create literals
if the backend is able to. (Done 2012/09/15).
• The ExpresionTemplate parameter could be defaulted to a traits class for more sensible defaults (done 2012/09/20).
• In a = exp1 op exp2 where a occurs inside one of exp1 or exp2 then we can optimise and eliminate one more temporary (done
2012/09/20).
Pre-Review Comments
• Make fixed precision orthogonal to Allocator type in cpp_int. Possible solution - add an additional MaxBits template argument
that defaults to 0 (meaning keep going till no more space/memory). Done.
• Can ring types (exact floating point types) be supported? The answer should be yes, but someone needs to write it (Moved to
TODO list).
• Should there be a choice of rounding mode (probably MPFR specific)? Moved to TODO list.
• Make the exponent type for cpp_dec_float a template parameter, maybe include support for big-integer exponents. Open question
- what should be the default - int32_t or int64_t? (done 2012/09/06)
• Be a bit clearer on the effects of sign-magnitude representation of cpp_int - min == -max etc - done.
• 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).
• Add support for fused multiply add (and subtract). GMP mpz_t could use this (done 2012/09/20).
FAQ
Why do I get compiler errors when Most likely you are actually passing an expression template type to the function and template-
passing a number to a template argument-deduction deduces the "wrong" type. Try casting the arguments involving expressions
function?
150
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 As a general rule, expression template support adds a small runtime overhead creating and
a performance gain? 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 op- Yes they do, sometimes quite radically so, if this is a concern then they should be turned off
erations? for the number type you are using.
I can't construct my number type Some conversions are explicit, that includes construction from a string, or constructing from
from some other type, but the docs any type that may result in loss of precision (for example constructing an integer type from a
indicate that the conversion should float).
be allowed, what's up?
Why do I get an exception thrown Bitwise operations on negative values (or indeed any signed integer type) are unspecified by
(or the program crash due to an un- the standard. As a result any attempt to carry out a bitwise operation on a negative checked-
caught exception) when using the integer will result in a std::range_error being thrown.
bitwise operators on a checked
cpp_int?
Why do I get compiler errors when Use of the complement operator on signed types is problematic as the result is unspecified by
trying to use the complement operat- the standard, and is further complicated by the fact that most extended precision integer types
or? 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/multi- This was deemed not to be practical: these algorithms are intimately tied to the actual data
plication algorithms? representation used.
Acknowledgements
This library would not have happened without:
• All the folks at GMP, MPFR and libtommath, for providing the "guts" that makes this library work.
• "The Art Of Computer Programming", Donald E. Knuth, Volume 2: Seminumerical Algorithms, Third Edition (Reading, Mas-
sachusetts: Addison-Wesley, 1997), xiv+762pp. ISBN 0-201-89684-2
151
Indexes
Function Index
A
abs
number, 84
add
Generic Integer Operations, 61
Mixed Precision Arithmetic, 59
number, 84
TODO, 150
assign
number, 84
assign_components
Optional Requirements on the Backend Type, 103
B
bits
Generating Random Numbers, 53
Input Output, 81
Rounding Rules for Conversions, 58
std::numeric_limits<> constants, 63
bit_flip
Generic Integer Operations, 61
number, 84
bit_set
Generic Integer Operations, 61
number, 84
bit_test
Generic Integer Operations, 61
number, 84
bit_unset
Generic Integer Operations, 61
number, 84
C
compare
number, 84
D
data
float128, 25
gmp_float, 21
gmp_int, 12
gmp_rational, 41
mpfi_float, 36
mpfr_float, 23
default_precision
number, 84
divide_qr
Generic Integer Operations, 61
number, 84
152
E
empty
mpfi_float, 36
eval_acos
Optional Requirements on the Backend Type, 103
eval_add
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_asin
Optional Requirements on the Backend Type, 103
eval_atan
Optional Requirements on the Backend Type, 103
eval_atan2
Optional Requirements on the Backend Type, 103
eval_bitwise_and
Optional Requirements on the Backend Type, 103
eval_bitwise_or
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_bitwise_xor
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_bit_flip
Optional Requirements on the Backend Type, 103
eval_bit_set
Optional Requirements on the Backend Type, 103
eval_bit_test
Optional Requirements on the Backend Type, 103
eval_bit_unset
Optional Requirements on the Backend Type, 103
eval_ceil
Compulsory Requirements on the Backend type., 103
eval_complement
Compulsory Requirements on the Backend type., 103
eval_convert_to
Compulsory Requirements on the Backend type., 103
eval_cos
Optional Requirements on the Backend Type, 103
eval_cosh
Optional Requirements on the Backend Type, 103
eval_decrement
Optional Requirements on the Backend Type, 103
eval_divide
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_eq
Optional Requirements on the Backend Type, 103
eval_exp
Optional Requirements on the Backend Type, 103
eval_fabs
Optional Requirements on the Backend Type, 103
eval_floor
Compulsory Requirements on the Backend type., 103
eval_fmod
Optional Requirements on the Backend Type, 103
eval_frexp
Compulsory Requirements on the Backend type., 103
153
eval_gcd
Optional Requirements on the Backend Type, 103
eval_get_sign
Optional Requirements on the Backend Type, 103
eval_gt
Optional Requirements on the Backend Type, 103
eval_increment
Optional Requirements on the Backend Type, 103
eval_integer_sqrt
Optional Requirements on the Backend Type, 103
eval_is_zero
Optional Requirements on the Backend Type, 103
eval_lcm
Optional Requirements on the Backend Type, 103
eval_ldexp
Compulsory Requirements on the Backend type., 103
eval_left_shift
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_log
Optional Requirements on the Backend Type, 103
eval_log10
Optional Requirements on the Backend Type, 103
eval_lt
Optional Requirements on the Backend Type, 103
eval_modulus
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_msb
Optional Requirements on the Backend Type, 103
eval_multiply
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_multiply_add
Optional Requirements on the Backend Type, 103
eval_multiply_subtract
Optional Requirements on the Backend Type, 103
eval_pow
Optional Requirements on the Backend Type, 103
eval_powm
Optional Requirements on the Backend Type, 103
eval_qr
Optional Requirements on the Backend Type, 103
eval_right_shift
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_round
Optional Requirements on the Backend Type, 103
eval_sin
Optional Requirements on the Backend Type, 103
eval_sinh
Optional Requirements on the Backend Type, 103
eval_sqrt
Compulsory Requirements on the Backend type., 103
eval_subtract
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_tan
154
F
fpclassify
number, 84
I
if
Primality Testing, 55
in
mpfi_float, 36
infinity
std::numeric_limits<> functions, 70
integer_modulus
Generic Integer Operations, 61
number, 84
iround
number, 84
isfinite
number, 84
isinf
number, 84
isnan
number, 84
isnormal
number, 84
itrunc
number, 84
L
llround
number, 84
lltrunc
number, 84
log_postfix_event
logged_adaptor, 44
log_prefix_event
logged_adaptor, 44
lround
number, 84
lsb
Generic Integer Operations, 61
number, 84
ltrunc
number, 84
M
max
std::numeric_limits<> constants, 63
std::numeric_limits<> functions, 70
miller_rabin_test
Generic Integer Operations, 61
number, 84
155
Primality Testing, 55
min
std::numeric_limits<> functions, 70
msb
Generic Integer Operations, 61
number, 84
multiply
Generic Integer Operations, 61
Mixed Precision Arithmetic, 59
number, 84
O
overlap
mpfi_float, 36
P
powm
Generic Integer Operations, 61
number, 84
precision
FAQ, 151
Generic Integer Operations, 61
Introduction, 3
number, 84
proper_subset
mpfi_float, 36
R
r
Bit Operations, 16
round
number, 84
S
sign
number, 84
singleton
mpfi_float, 36
sqrt
Generic Integer Operations, 61
number, 84
std::numeric_limits<> functions, 70
str
number, 84
subset
mpfi_float, 36
subtract
Generic Integer Operations, 61
Mixed Precision Arithmetic, 59
number, 84
swap
number, 84
T
trunc
number, 84
156
two
std::numeric_limits<> constants, 63
V
value
cpp_bin_float, 101
number, 84
std::numeric_limits<> functions, 70
Z
zero
gmp_float, 22
gmp_int, 13
gmp_rational, 42
std::numeric_limits<> constants, 69
tommath_rational, 43
tom_int, 14
zero_in
mpfi_float, 36
Class Index
C
component_type
number, 84
cpp_bin_float
cpp_bin_float, 18, 100
cpp_dec_float
cpp_dec_float, 20, 102
cpp_int_backend
cpp_int, 9, 97
D
debug_adaptor
debug_adaptor, 46
E
expression_template_default
number, 84
F
float128_backend
float128, 25
G
gmp_float
gmp_float, 21, 99
gmp_int
gmp_int, 12, 98
gmp_rational
gmp_rational, 41
I
is_explicitly_convertible
Internal Support Code, 102
157
is_lossy_conversion
Internal Support Code, 102
is_number
number, 84
is_number_expression
number, 84
is_restricted_conversion
Internal Support Code, 102
is_signed_number
Internal Support Code, 102
is_unsigned_number
Internal Support Code, 102
L
logged_adaptor
logged_adaptor, 44
M
mpfi_float_backend
mpfi_float, 36
mpfr_float_backend
mpfr_float, 23, 100
mpfr_float_backend, 100
N
number
number, 84
number_category
number, 84
T
tommath_int
tom_int, 13, 99
Typedef Index
C
checked_cpp_int
cpp_int, 9, 97
checked_cpp_rational
cpp_int, 9, 97
checked_cpp_rational_backend
cpp_int, 9, 97
checked_int1024_t
cpp_int, 9, 97
checked_int128_t
cpp_int, 9, 97
checked_int256_t
cpp_int, 9, 97
checked_int512_t
cpp_int, 9, 97
checked_uint1024_t
cpp_int, 9, 97
checked_uint128_t
cpp_int, 9, 97
checked_uint256_t
158
cpp_int, 9, 97
checked_uint512_t
cpp_int, 9, 97
cpp_bin_float_100
cpp_bin_float, 18, 100
cpp_bin_float_50
cpp_bin_float, 18, 100
cpp_bin_float_double
cpp_bin_float, 18, 100
cpp_bin_float_double_extended
cpp_bin_float, 18, 100
cpp_bin_float_quad
cpp_bin_float, 18, 100
cpp_bin_float_single
cpp_bin_float, 18, 100
cpp_dec_float_100
cpp_dec_float, 20, 102
cpp_dec_float_50
cpp_dec_float, 20, 102
std::numeric_limits<> constants, 63
std::numeric_limits<> functions, 70
cpp_int
cpp_int, 9, 97
cpp_rational
cpp_int, 9, 97
cpp_rational, 40
cpp_rational_backend
cpp_int, 9, 97
cpp_rational, 40
F
float128
float128, 25
std::numeric_limits<> constants, 63
I
int1024_t
cpp_int, 9, 97
int128_t
cpp_int, 9, 97
int256_t
cpp_int, 9, 97
int512_t
cpp_int, 9, 97
int_type
Primality Testing, 55
L
limb_type
cpp_int, 9, 97
M
mpfi_float
mpfi_float, 36
mpfi_float_1000
mpfi_float, 36
mpfi_float_50
159
mpfi_float, 36
mpfr_float
mpfr_float, 23
mpfr_float_backend, 23, 100
mpfr_float_100
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_1000
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_50
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_500
mpfr_float, 23
mpfr_float_backend, 100
mpf_float
gmp_float, 21, 99
mpf_float_100
gmp_float, 21, 99
mpf_float_1000
gmp_float, 21, 99
mpf_float_50
gmp_float, 21, 99
mpf_float_500
gmp_float, 21, 99
mpq_rational
gmp_rational, 41
mpz_int
gmp_int, 12, 98
mp_type
Calculating an Integral, 32
Polynomial Evaluation, 34
S
static_mpfr_float_100
mpfr_float, 23
static_mpfr_float_50
mpfr_float, 23
T
tommath_rational
tommath_rational, 42
tom_int
tom_int, 13, 99
tom_rational
tommath_rational, 42
U
uint1024_t
cpp_int, 9, 97
uint128_t
cpp_int, 9, 97
uint256_t
cpp_int, 9, 97
uint512_t
cpp_int, 9, 97
160
Index
A
abs
number, 84
add
Generic Integer Operations, 61
Mixed Precision Arithmetic, 59
number, 84
TODO, 150
assign
number, 84
assign_components
Optional Requirements on the Backend Type, 103
B
Bit Operations
r, 16
bits
Generating Random Numbers, 53
Input Output, 81
Rounding Rules for Conversions, 58
std::numeric_limits<> constants, 63
bit_flip
Generic Integer Operations, 61
number, 84
bit_set
Generic Integer Operations, 61
number, 84
bit_test
Generic Integer Operations, 61
number, 84
bit_unset
Generic Integer Operations, 61
number, 84
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL
Literal Types and constexpr Support, 56
BOOST_MP_MIN_EXPONENT_DIGITS
Input Output, 81
BOOST_MP_USE_FLOAT128
float128, 26
BOOST_MP_USE_QUAD
float128, 26
C
Calculating an Integral
mp_type, 32
checked_cpp_int
cpp_int, 9, 97
checked_cpp_rational
cpp_int, 9, 97
checked_cpp_rational_backend
cpp_int, 9, 97
checked_int1024_t
cpp_int, 9, 97
checked_int128_t
161
cpp_int, 9, 97
checked_int256_t
cpp_int, 9, 97
checked_int512_t
cpp_int, 9, 97
checked_uint1024_t
cpp_int, 9, 97
checked_uint128_t
cpp_int, 9, 97
checked_uint256_t
cpp_int, 9, 97
checked_uint512_t
cpp_int, 9, 97
compare
number, 84
component_type
number, 84
Compulsory Requirements on the Backend type.
eval_add, 103
eval_bitwise_or, 103
eval_bitwise_xor, 103
eval_ceil, 103
eval_complement, 103
eval_convert_to, 103
eval_divide, 103
eval_floor, 103
eval_frexp, 103
eval_ldexp, 103
eval_left_shift, 103
eval_modulus, 103
eval_multiply, 103
eval_right_shift, 103
eval_sqrt, 103
eval_subtract, 103
cpp_bin_float
cpp_bin_float, 18, 100
cpp_bin_float_100, 18, 100
cpp_bin_float_50, 18, 100
cpp_bin_float_double, 18, 100
cpp_bin_float_double_extended, 18, 100
cpp_bin_float_quad, 18, 100
cpp_bin_float_single, 18, 100
value, 101
cpp_bin_float_100
cpp_bin_float, 18, 100
cpp_bin_float_50
cpp_bin_float, 18, 100
cpp_bin_float_double
cpp_bin_float, 18, 100
cpp_bin_float_double_extended
cpp_bin_float, 18, 100
cpp_bin_float_quad
cpp_bin_float, 18, 100
cpp_bin_float_single
cpp_bin_float, 18, 100
cpp_dec_float
cpp_dec_float, 20, 102
cpp_dec_float_100, 20, 102
162
D
data
float128, 25
gmp_float, 21
gmp_int, 12
gmp_rational, 41
mpfi_float, 36
mpfr_float, 23
debug_adaptor
debug_adaptor, 46
default_precision
number, 84
divide_qr
Generic Integer Operations, 61
number, 84
163
E
empty
mpfi_float, 36
eval_acos
Optional Requirements on the Backend Type, 103
eval_add
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_asin
Optional Requirements on the Backend Type, 103
eval_atan
Optional Requirements on the Backend Type, 103
eval_atan2
Optional Requirements on the Backend Type, 103
eval_bitwise_and
Optional Requirements on the Backend Type, 103
eval_bitwise_or
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_bitwise_xor
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_bit_flip
Optional Requirements on the Backend Type, 103
eval_bit_set
Optional Requirements on the Backend Type, 103
eval_bit_test
Optional Requirements on the Backend Type, 103
eval_bit_unset
Optional Requirements on the Backend Type, 103
eval_ceil
Compulsory Requirements on the Backend type., 103
eval_complement
Compulsory Requirements on the Backend type., 103
eval_convert_to
Compulsory Requirements on the Backend type., 103
eval_cos
Optional Requirements on the Backend Type, 103
eval_cosh
Optional Requirements on the Backend Type, 103
eval_decrement
Optional Requirements on the Backend Type, 103
eval_divide
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_eq
Optional Requirements on the Backend Type, 103
eval_exp
Optional Requirements on the Backend Type, 103
eval_fabs
Optional Requirements on the Backend Type, 103
eval_floor
Compulsory Requirements on the Backend type., 103
eval_fmod
Optional Requirements on the Backend Type, 103
eval_frexp
Compulsory Requirements on the Backend type., 103
164
eval_gcd
Optional Requirements on the Backend Type, 103
eval_get_sign
Optional Requirements on the Backend Type, 103
eval_gt
Optional Requirements on the Backend Type, 103
eval_increment
Optional Requirements on the Backend Type, 103
eval_integer_sqrt
Optional Requirements on the Backend Type, 103
eval_is_zero
Optional Requirements on the Backend Type, 103
eval_lcm
Optional Requirements on the Backend Type, 103
eval_ldexp
Compulsory Requirements on the Backend type., 103
eval_left_shift
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_log
Optional Requirements on the Backend Type, 103
eval_log10
Optional Requirements on the Backend Type, 103
eval_lt
Optional Requirements on the Backend Type, 103
eval_modulus
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_msb
Optional Requirements on the Backend Type, 103
eval_multiply
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_multiply_add
Optional Requirements on the Backend Type, 103
eval_multiply_subtract
Optional Requirements on the Backend Type, 103
eval_pow
Optional Requirements on the Backend Type, 103
eval_powm
Optional Requirements on the Backend Type, 103
eval_qr
Optional Requirements on the Backend Type, 103
eval_right_shift
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_round
Optional Requirements on the Backend Type, 103
eval_sin
Optional Requirements on the Backend Type, 103
eval_sinh
Optional Requirements on the Backend Type, 103
eval_sqrt
Compulsory Requirements on the Backend type., 103
eval_subtract
Compulsory Requirements on the Backend type., 103
Optional Requirements on the Backend Type, 103
eval_tan
165
F
FAQ
precision, 151
float128
BOOST_MP_USE_FLOAT128, 26
BOOST_MP_USE_QUAD, 26
data, 25
float128, 25
float128_backend, 25
std::numeric_limits<> constants, 63
float128_backend
float128, 25
fpclassify
number, 84
G
Generating Random Numbers
bits, 53
Generic Integer Operations
add, 61
bit_flip, 61
bit_set, 61
bit_test, 61
bit_unset, 61
divide_qr, 61
integer_modulus, 61
lsb, 61
miller_rabin_test, 61
msb, 61
multiply, 61
powm, 61
precision, 61
sqrt, 61
subtract, 61
gmp_float
data, 21
gmp_float, 21, 99
mpf_float, 21, 99
mpf_float_100, 21, 99
mpf_float_1000, 21, 99
mpf_float_50, 21, 99
mpf_float_500, 21, 99
zero, 22
gmp_int
data, 12
gmp_int, 12, 98
mpz_int, 12, 98
zero, 13
gmp_rational
166
data, 41
gmp_rational, 41
mpq_rational, 41
zero, 42
I
if
Primality Testing, 55
in
mpfi_float, 36
infinity
std::numeric_limits<> functions, 70
Input Output
bits, 81
BOOST_MP_MIN_EXPONENT_DIGITS, 81
int1024_t
cpp_int, 9, 97
int128_t
cpp_int, 9, 97
int256_t
cpp_int, 9, 97
int512_t
cpp_int, 9, 97
integer_modulus
Generic Integer Operations, 61
number, 84
Internal Support Code
is_explicitly_convertible, 102
is_lossy_conversion, 102
is_restricted_conversion, 102
is_signed_number, 102
is_unsigned_number, 102
Introduction
precision, 3
int_type
Primality Testing, 55
iround
number, 84
isfinite
number, 84
isinf
number, 84
isnan
number, 84
isnormal
number, 84
is_explicitly_convertible
Internal Support Code, 102
is_lossy_conversion
Internal Support Code, 102
is_number
number, 84
is_number_expression
number, 84
is_restricted_conversion
Internal Support Code, 102
is_signed_number
167
L
limb_type
cpp_int, 9, 97
Literal Types and constexpr Support
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL, 56
llround
number, 84
lltrunc
number, 84
logged_adaptor
logged_adaptor, 44
log_postfix_event, 44
log_prefix_event, 44
log_postfix_event
logged_adaptor, 44
log_prefix_event
logged_adaptor, 44
lround
number, 84
lsb
Generic Integer Operations, 61
number, 84
ltrunc
number, 84
M
max
std::numeric_limits<> constants, 63
std::numeric_limits<> functions, 70
miller_rabin_test
Generic Integer Operations, 61
number, 84
Primality Testing, 55
min
std::numeric_limits<> functions, 70
Mixed Precision Arithmetic
add, 59
multiply, 59
subtract, 59
mpfi_float
data, 36
empty, 36
in, 36
mpfi_float, 36
mpfi_float_1000, 36
mpfi_float_50, 36
mpfi_float_backend, 36
overlap, 36
proper_subset, 36
singleton, 36
subset, 36
168
zero_in, 36
mpfi_float_1000
mpfi_float, 36
mpfi_float_50
mpfi_float, 36
mpfi_float_backend
mpfi_float, 36
mpfr_float
data, 23
mpfr_float, 23
mpfr_float_100, 23
mpfr_float_1000, 23
mpfr_float_50, 23
mpfr_float_500, 23
mpfr_float_backend, 23, 100
static_mpfr_float_100, 23
static_mpfr_float_50, 23
mpfr_float_100
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_1000
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_50
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_500
mpfr_float, 23
mpfr_float_backend, 100
mpfr_float_backend
mpfr_float, 23, 100
mpfr_float_100, 100
mpfr_float_1000, 100
mpfr_float_50, 100
mpfr_float_500, 100
mpfr_float_backend, 100
mpf_float
gmp_float, 21, 99
mpf_float_100
gmp_float, 21, 99
mpf_float_1000
gmp_float, 21, 99
mpf_float_50
gmp_float, 21, 99
mpf_float_500
gmp_float, 21, 99
mpq_rational
gmp_rational, 41
mpz_int
gmp_int, 12, 98
mp_type
Calculating an Integral, 32
Polynomial Evaluation, 34
msb
Generic Integer Operations, 61
number, 84
multiply
Generic Integer Operations, 61
169
N
number
abs, 84
add, 84
assign, 84
bit_flip, 84
bit_set, 84
bit_test, 84
bit_unset, 84
compare, 84
component_type, 84
default_precision, 84
divide_qr, 84
expression_template_default, 84
fpclassify, 84
integer_modulus, 84
iround, 84
isfinite, 84
isinf, 84
isnan, 84
isnormal, 84
is_number, 84
is_number_expression, 84
itrunc, 84
llround, 84
lltrunc, 84
lround, 84
lsb, 84
ltrunc, 84
miller_rabin_test, 84
msb, 84
multiply, 84
number, 84
number_category, 84
powm, 84
precision, 84
round, 84
sign, 84
sqrt, 84
str, 84
subtract, 84
swap, 84
trunc, 84
value, 84
number_category
number, 84
O
Optional Requirements on the Backend Type
assign_components, 103
eval_acos, 103
eval_add, 103
eval_asin, 103
eval_atan, 103
170
eval_atan2, 103
eval_bitwise_and, 103
eval_bitwise_or, 103
eval_bitwise_xor, 103
eval_bit_flip, 103
eval_bit_set, 103
eval_bit_test, 103
eval_bit_unset, 103
eval_cos, 103
eval_cosh, 103
eval_decrement, 103
eval_divide, 103
eval_eq, 103
eval_exp, 103
eval_fabs, 103
eval_fmod, 103
eval_gcd, 103
eval_get_sign, 103
eval_gt, 103
eval_increment, 103
eval_integer_sqrt, 103
eval_is_zero, 103
eval_lcm, 103
eval_left_shift, 103
eval_log, 103
eval_log10, 103
eval_lt, 103
eval_modulus, 103
eval_msb, 103
eval_multiply, 103
eval_multiply_add, 103
eval_multiply_subtract, 103
eval_pow, 103
eval_powm, 103
eval_qr, 103
eval_right_shift, 103
eval_round, 103
eval_sin, 103
eval_sinh, 103
eval_subtract, 103
eval_tan, 103
eval_tanh, 103
eval_trunc, 103
overlap
mpfi_float, 36
P
Polynomial Evaluation
mp_type, 34
powm
Generic Integer Operations, 61
number, 84
precision
FAQ, 151
Generic Integer Operations, 61
Introduction, 3
number, 84
171
Primality Testing
if, 55
int_type, 55
miller_rabin_test, 55
proper_subset
mpfi_float, 36
R
r
Bit Operations, 16
round
number, 84
Rounding Rules for Conversions
bits, 58
S
sign
number, 84
singleton
mpfi_float, 36
sqrt
Generic Integer Operations, 61
number, 84
std::numeric_limits<> functions, 70
static_mpfr_float_100
mpfr_float, 23
static_mpfr_float_50
mpfr_float, 23
std::numeric_limits<> constants
bits, 63
cpp_dec_float_50, 63
float128, 63
max, 63
two, 63
zero, 69
std::numeric_limits<> functions
cpp_dec_float_50, 70
infinity, 70
max, 70
min, 70
sqrt, 70
value, 70
str
number, 84
subset
mpfi_float, 36
subtract
Generic Integer Operations, 61
Mixed Precision Arithmetic, 59
number, 84
swap
number, 84
T
TODO
add, 150
tommath_int
172
tom_int, 13, 99
tommath_rational
tommath_rational, 42
tom_rational, 42
zero, 43
tom_int
tommath_int, 13, 99
tom_int, 13, 99
zero, 14
tom_rational
tommath_rational, 42
trunc
number, 84
two
std::numeric_limits<> constants, 63
U
uint1024_t
cpp_int, 9, 97
uint128_t
cpp_int, 9, 97
uint256_t
cpp_int, 9, 97
uint512_t
cpp_int, 9, 97
V
value
cpp_bin_float, 101
number, 84
std::numeric_limits<> functions, 70
Z
zero
gmp_float, 22
gmp_int, 13
gmp_rational, 42
std::numeric_limits<> constants, 69
tommath_rational, 43
tom_int, 14
zero_in
mpfi_float, 36
173