Literals
The following literals and macro are provided for convenient construction of the type provided in the library.
#include <boost/int256/literals.hpp>
namespace boost {
namespace int256 {
namespace literals {
BOOST_INT256_HOST_DEVICE constexpr uint256 operator ""_u256(const char* str) noexcept;
BOOST_INT256_HOST_DEVICE constexpr uint256 operator ""_U256(const char* str) noexcept;
BOOST_INT256_HOST_DEVICE constexpr uint256 operator ""_u256(const char* str, std::size_t len) noexcept;
BOOST_INT256_HOST_DEVICE constexpr uint256 operator ""_U256(const char* str, std::size_t len) noexcept;
BOOST_INT256_HOST_DEVICE constexpr int256 operator ""_i256(const char* str) noexcept;
BOOST_INT256_HOST_DEVICE constexpr int256 operator ""_I256(const char* str) noexcept;
BOOST_INT256_HOST_DEVICE constexpr int256 operator ""_i256(const char* str, std::size_t len) noexcept;
BOOST_INT256_HOST_DEVICE constexpr int256 operator ""_I256(const char* str, std::size_t len) noexcept;
} // namespace literals
} // namespace int256
} // namespace boost
#define BOOST_INT256_UINT256_C(x) ...
#define BOOST_INT256_INT256_C(x) ...
The macros at the end allow you to write out a 256-bit number the way you would with UINT64_C, without having to add quotes.
They are defined in <boost/int256/detail/literal_macros.hpp>, which literals.hpp includes, and need no using namespace.
The signed operators are noexcept.
A malformed or out-of-range literal used in a constant expression is a compile-time error.
One that is only evaluated at run time, for example by calling the string form with a run-time string, has no value to return and terminates the program.
Bases
The literals accept the standard C++ integer base prefixes in addition to plain decimal.
A 0x or 0X prefix selects hexadecimal, 0b or 0B selects binary, and a leading 0 selects octal.
The prefix is stripped and the remaining digits are parsed in the selected base.
Digit separators (') may be used in any base.
0xDEAD'BEEF_u256 // hexadecimal, == 3735928559
0b1111'0000_u256 // binary, == 240
0777_u256 // octal, == 511
255_u256 // decimal, == 255
"115792089237316195423570985008687907853269984665640564039457584007913129639935"_u256 // the max
-0xFF_i256 // == -255 (the unary minus is applied after parsing)
"-0b1010"_i256 // == -10 (the string form may embed the sign)
A raw (unquoted) _i256 literal never sees a leading -: -X_i256 is the unary minus operator applied to the result of X_i256, exactly as -9223372036854775808LL is unary minus applied to 9223372036854775808LL.
So X itself, with no sign, has to fit in int256’s positive range in whichever base it is written, the same rule a built-in literal and Boost.Int128’s `_i128 follow.
This means the positive magnitude of the minimum value, 2255, is one more than INT256_MAX, so all of the following are ill-formed and none of them may wrap to a valid value:
57896044618658097711785492504343953926634992332820282019728792003956564819968_i256 // 2^255, ill-formed: > MAX
0x8000000000000000000000000000000000000000000000000000000000000000_i256 // 2^255, ill-formed: > MAX
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_i256 // 2^256 - 1, ill-formed: > MAX
A quoted string literal is different: the sign is part of the digit sequence the operator receives, so it is parsed together with the magnitude by parse_literal, which range-checks the signed value directly (allowing a magnitude up to 2255 when the sign is negative, and up to 2255 - 1 when it is not).
The macro forms stringify their whole argument, sign included, so they get the same treatment.
These are the only ways to reach the minimum value directly:
BOOST_INT256_INT256_MIN
BOOST_INT256_INT256_C(-57896044618658097711785492504343953926634992332820282019728792003956564819968)
BOOST_INT256_INT256_C(-0x8000000000000000000000000000000000000000000000000000000000000000)
"-0x8000000000000000000000000000000000000000000000000000000000000000"_i256
"-57896044618658097711785492504343953926634992332820282019728792003956564819968"_i256
Error Handling
An invalid literal is rejected at compile time rather than being silently accepted.
This includes a value that overflows the type, a digit that is not valid for the selected base (for example 0b2 or 09), and an empty magnitude such as 0x.
When such a literal is used in a constant expression the parse reaches BOOST_INT256_UNREACHABLE, which is not a constant expression and therefore is a hard compile error.
The maximum is accepted and one past it is rejected, so ...639935_u256 compiles and ...639936_u256 does not.
The minimum int256 value cannot be written as a negated raw _i256 literal for the reason given above: its positive magnitude (2255) exceeds INT256_MAX, so the literal is rejected before the unary minus ever applies. Use BOOST_INT256_INT256_MIN, one of the string or macro forms shown above, or (std::numeric_limits<int256>::min)() instead.
|
See the construction examples for usage demonstrations of both the literals and the macros.
Design Rationale
All of the user-defined literals provided by the library are string-form: the operator receives a const char* and parses the digit sequence.
This holds even for raw numeric tokens like 12345_U256, which the compiler forwards to the operator as the string "12345".
The choice is intentional.
A 256-bit value cannot be represented by unsigned long long, so any literal whose magnitude exceeds 264 must go through a string-based parse.
Providing only the string form means there is a single overload that handles every magnitude uniformly, rather than a numeric form for small values and a string form for large ones with a hard cutoff at 264.
The API is the same regardless of how large the value is.
The trade-off is that every literal pays the cost of parsing, even when the value would fit in a built-in integer.
For values smaller than 264, prefer the constructor:
constexpr uint256 small {42U}; // direct conversion from a builtin
const auto small_literal {42_U256}; // parses "42" and then constructs
The two produce the same value, but the constructor avoids the parse and should be used in hot paths or in code where many small constants are constructed.