Literals
The following literals and macros are provided for convenient construction of the types provided in the library.
#include <boost/int128/literals.hpp>
namespace boost {
namespace int128 {
namespace literals {
BOOST_INT128_HOST_DEVICE constexpr uint128 operator ""_u128(const char* str) noexcept;
BOOST_INT128_HOST_DEVICE constexpr uint128 operator ""_U128(const char* str) noexcept;
BOOST_INT128_HOST_DEVICE constexpr uint128 operator ""_u128(const char* str, std::size_t len) noexcept;
BOOST_INT128_HOST_DEVICE constexpr uint128 operator ""_U128(const char* str, std::size_t len) noexcept;
BOOST_INT128_HOST_DEVICE constexpr int128 operator ""_i128(const char* str) noexcept;
BOOST_INT128_HOST_DEVICE constexpr int128 operator ""_I128(const char* str) noexcept;
BOOST_INT128_HOST_DEVICE constexpr int128 operator ""_i128(const char* str, std::size_t len) noexcept;
BOOST_INT128_HOST_DEVICE constexpr int128 operator ""_I128(const char* str, std::size_t len) noexcept;
} // namespace literals
} // namespace int128
} // namespace boost
#define BOOST_INT128_UINT128_C(x) ...
#define BOOST_INT128_INT128_C(x) ...
The macros at the end allow you to write out a 128-bit number like you would with say UINT64_C without having to add quotes.
The 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_u128 // hexadecimal, == 3735928559
0b1111'0000_u128 // binary, == 240
0777_u128 // octal, == 511
255_u128 // decimal, == 255
-0xFF_i128 // == -255 (the unary minus is applied after parsing)
"-0b1010"_i128 // == -10 (the string form may embed the sign)
A raw (unquoted) _i128 literal never sees a leading -: -X_i128 is the unary minus operator applied to the result of X_i128, exactly as -9223372036854775808LL is unary minus applied to 9223372036854775808LL.
So X itself, with no sign, has to fit in int128’s positive range in whichever base it is written, the same rule a built-in literal follows.
This means the positive magnitude of the minimum value, `2127, is one more than INT128_MAX, so all of the following are ill-formed and none of them may wrap to a valid value:
170141183460469231731687303715884105728_i128 // 2^127, ill-formed: > MAX
0x80000000000000000000000000000000_i128 // 2^127, ill-formed: > MAX
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF_i128 // 2^128 - 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, which range-checks the signed value directly (allowing a magnitude up to 2127 when the sign is negative, and up to 2127 - 1 when it is not).
The macro form stringifies its whole argument, sign included, so it gets the same treatment.
These are the only ways to reach the minimum value directly:
BOOST_INT128_INT128_MIN
BOOST_INT128_INT128_C(-170141183460469231731687303715884105728)
BOOST_INT128_INT128_C(-0x80000000000000000000000000000000)
"-0x80000000000000000000000000000000"_i128
"-170141183460469231731687303715884105728"_i128
Error Handling
An invalid literal is rejected at compile time rather than being silently accepted.
This includes a value that overflows the target 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_INT128_UNREACHABLE, which is not a constant expression and therefore is a hard compile error.
The minimum int128 value cannot be written as a negated raw _i128 literal for the reason given above: its positive magnitude (2127) exceeds INT128_MAX, so the literal is rejected before the unary minus ever applies. Use BOOST_INT128_INT128_MIN, one of the string or macro forms shown above, or (std::numeric_limits<int128>::min)() instead.
|
See the construction examples for usage demonstrations of both literals and 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 via from_chars.
This holds even for raw numeric tokens like 12345_U128, which the compiler forwards to the operator as the string "12345".
The choice is intentional.
A 128-bit value cannot be represented by unsigned long long, so any literal whose magnitude exceeds 2^64 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 2^64.
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 builtin integer.
For values smaller than 2^64, prefer the constructor:
constexpr uint128 small {42U}; // direct conversion from a builtin
const auto small_literal {42_U128}; // 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.