1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
[/
Copyright 2011 - 2020 John Maddock.
Copyright 2013 - 2019 Paul A. Bristow.
Copyright 2013 Christopher Kormanyos.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:lits Literal Types and `constexpr` Support]
There are two kinds of `constexpr` support in this library:
* The more basic version requires only C++11 and allow the construction of some number types as literals.
* The more advanced support permits constexpr arithmetic and requires at least C++14
constexpr support, and for many operations C++2a support
[h4 Declaring numeric literals]
There are two backend types which are literals:
* __float128__ (which requires GCC), and
* Instantiations of `cpp_int_backend` where the Allocator parameter is type `void`.
In addition, prior to C++14 the Checked parameter must be `boost::multiprecision::unchecked`.
For example:
using namespace boost::multiprecision;
constexpr float128 f = 0.1Q // OK, float128's are always literals in C++11
constexpr int128_t i = 0; // OK, fixed precision int128_t has no allocator.
constexpr uint1024_t j = 0xFFFFFFFF00000000uLL; // OK, fixed precision uint1024_t has no allocator.
constexpr checked_uint128_t k = 1; // OK from C++14 and later, not supported for C++11.
constexpr checked_uint128_t k = -1; // Error, as this would normally lead to a runtime failure (exception).
constexpr cpp_int l = 2; // Error, type is not a literal as it performs memory management.
There is also support for user defined-literals with __cpp_int - these are limited to unchecked, fixed precision `cpp_int`'s
which are specified in hexadecimal notation. The suffixes supported are:
[table
[[Suffix][Meaning]]
[[_cppi][Specifies a value of type: `number<cpp_int_backend<N,N,signed_magnitude,unchecked,void> >`, where N is chosen
to contain just enough digits to hold the number specified.]]
[[_cppui][Specifies a value of type: `number<cpp_int_backend<N,N,unsigned_magnitude,unchecked,void> >`, where N is chosen
to contain just enough digits to hold the number specified.]]
[[_cppi['N]][Specifies a value of type `number<cpp_int_backend<N,N,signed_magnitude,unchecked,void> >`.]]
[[_cppui['N]][Specifies a value of type `number<cpp_int_backend<N,N,signed_magnitude,unchecked,void> >`.]]
]
In each case, use of these suffixes with hexadecimal values produces a `constexpr` result.
Examples:
// Any use of user defined literals requires that we import the literal-operators into current scope first:
using namespace boost::multiprecision::literals;
//
// To keep things simple in the example, we'll make our types used visible to this scope as well:
using namespace boost::multiprecision;
//
// The value zero as a number<cpp_int_backend<4,4,signed_magnitude,unchecked,void> >:
constexpr auto a = 0x0_cppi;
// The type of each constant has 4 bits per hexadecimal digit,
// so this is of type uint256_t (ie number<cpp_int_backend<256,256,unsigned_magnitude,unchecked,void> >):
constexpr auto b = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cppui;
//
// Smaller values can be assigned to larger values:
int256_t c = 0x1234_cppi; // OK
//
// However, this only works in constexpr contexts from C++14 onwards:
constexpr int256_t d = 0x1_cppi; // Compiler error in C++11, requires C++14
//
// Constants can be padded out with leading zeros to generate wider types:
constexpr uint256_t e = 0x0000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFF_cppui; // OK
//
// However, specific-width types are best produced with specific-width suffixes,
// ones supported by default are `_cpp[u]i128`, `_cpp[u]i256`, `_cpp[u]i512`, `_cpp[u]i1024`.
//
constexpr int128_t f = 0x1234_cppi128; // OK, always produces an int128_t as the result.
constexpr uint1024_t g = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccc_cppui1024; // OK,
// always produces an uint1024_t as the result.
//
// If other specific-width types are required, then there is a macro for generating the operators for these.
// The macro can be used at namespace scope only:
//
BOOST_MP_DEFINE_SIZED_CPP_INT_LITERAL(2048);
//
// Now we can create 2048-bit literals as well:
constexpr auto h = 0xff_cppi2048; // h is of type number<cpp_int_backend<2048,2048,signed_magnitude,unchecked,void> >
//
// Finally, negative values are handled via the unary minus operator:
//
constexpr int1024_t i = -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_cppui1024;
//
// Which means this also works:
constexpr int1024_t j = -g; // OK: unary minus operator is constexpr.
[h4 constexpr arithmetic]
The front end of the library is all `constexpr` from C++14 and later. Currently there are only two
backend types that are `constexpr` aware: __float128 and __cpp_int. More backends will follow at a later date.
Provided the compiler is GCC, type __float128__ support `constexpr` operations on all arithmetic operations from C++14, comparisons,
`abs`, `fabs`, `fpclassify`, `isnan`, `isinf`, `isfinite` and `isnormal` are also fully supported, but the transcendental functions are not.
The __cpp_int types support constexpr arithmetic, provided it is a fixed precision type with no allocator. It may also
be a checked integer: in which case a compiler error will be generated on overflow or undefined behaviour. In addition
the free functions `abs`, `swap`, `multiply`, `add`, `subtract`, `divide_qr`, `integer_modulus`, `powm`, `lsb`, `msb`,
`bit_test`, `bit_set`, `bit_unset`, `bit_flip`, `sqrt`, `gcd`, `lcm` are all supported. Use of __cpp_int in this way
requires either a C++2a compiler (one which supports `std::is_constant_evaluated()` - currently only gcc-9 or clang-9 or later),
or GCC-6 or later in C++14 mode.
Compilers other than GCC and without `std::is_constant_evaluated()` will support a very limited set of operations:
expect to hit roadblocks rather easily.
See __compiler_support for __is_constant_evaluated;
For example given:
[constexpr_circle]
We can now calculate areas and circumferences, using all compile-time `constexpr` arithmetic:
[constexpr_circle_usage]
Note that these make use of the numeric constants from the __math_constants library, which also happen to be `constexpr`.
These usually have the full precision of the floating-point type, here 128-bit, about 36 decimal digits.
[h5:hermite_poly_coeffics Calculating Hermite Polynomial coefficients at compile time]
For a more interesting example, in [@../../example/constexpr_float_arithmetic_examples.cpp constexpr_float_arithmetic_examples.cpp]
we define a simple class for `constexpr` polynomial arithmetic:
template <class T, unsigned Order>
struct const_polynomial;
Given this, we can use recurrence relations to calculate the coefficients for various orthogonal
polynomials - in the example we use the Hermite polynomials. Only the constructor does any work -
it uses the recurrence relations to calculate the coefficient array:
[hermite_example]
Now we just need to define ['H[sub 0]] and ['H[sub 1]] as termination conditions for the recurrence:
[hermite_example2]
We can now declare ['H[sub 9]] as a `constexpr` object, access the coefficients, and evaluate
at an abscissa value, all at compile-time using `constexpr` arithmetic:
[hermite_example3]
See [@../../example/constexpr_float_arithmetic_examples.cpp constexpr_float_arithmetic_examples.cpp] for working code.
Also since the coefficients to the Hermite polynomials are integers, we can also generate the Hermite
coefficients using (fixed precision) `cpp_int`s: see [@../../test/constexpr_test_cpp_int_6.cpp constexpr_test_cpp_int_6.cpp].
[h5:factorial_constexpr `constexpr` Factorials]
We can also generate integer factorials in [@../../test/constexpr_test_cpp_int_5.cpp constexpr_test_cpp_int_5.cpp] like so:
[factorial_decl]
and validate the result:
constexpr uint1024_t f1 = factorial(uint1024_t(31)); // Factorial 31!
static_assert(f1 == 0x1956ad0aae33a4560c5cd2c000000_cppi); // Expected result as an Boost.Multiprecision integer literal.
[h5:random_constexpr Random `constexpr` values]
Another example in [@../../test/constexpr_test_cpp_int_7.cpp constexpr_test_cpp_int_7.cpp] generates
a fresh multiprecision random number each time the file is compiled. It includes an C++ template implementation of the
[@https://en.wikipedia.org/wiki/KISS_(algorithm) KISS random number algorithm by George Marsaglia] for `cpp_int` integers.
[random_constexpr_cppint]
See also the __random section.
[endsect] [/section:lits Literal Types and `constexpr` Support]
|