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