The big_int Type
Design
The most important anchor points of the design of the big_int type are:
-
big_intshould be elastic; that is, it should grow to the necessary size required to fit the result of an arithmetic operation. -
big_intshould support custom allocators. -
big_intshould expose small-object optimization to the user.
This leads us to the following type declarations:
namespace beman::big_int {
// uint_multiprecision_t is the unsigned integer used to store each "limb"
// (machine-word digit) of the magnitude of a big_int.
#if ... // 32-bit limb platform detected
using uint_multiprecision_t = unsigned int;
#else // 64-bit limb platform detected
using uint_multiprecision_t = unsigned long long;
#endif
} // namespace beman::big_int
// min_inplace_bits is the number of bits of statically allocated storage that
// the basic_big_int will have available for the small-object optimization.
template <std::size_t min_inplace_bits, class Allocator = std::allocator<uint_multiprecision_t>>
class basic_big_int;
// Default specialization with a stateless allocator.
using big_int = basic_big_int<64, std::allocator<uint_multiprecision_t>>;
namespace pmr {
// Specialization parameterized on std::pmr::polymorphic_allocator.
template <std::size_t b>
using basic_big_int = beman::big_int::basic_big_int<b, std::pmr::polymorphic_allocator<uint_multiprecision_t>>;
using big_int = basic_big_int</* same in-place bits as the default big_int */>;
} // namespace pmr
} // namespace beman::big_int
A basic_big_int stores its magnitude as a little-endian sequence of
uint_multiprecision_t limbs (the first limb holds the least significant bits)
together with a separate sign. Values whose magnitude fits within
inplace_bits bits are stored directly inside the object; larger values are
stored in allocator-provided dynamic storage.
Synopsis
In the synopsis below, the italicized names (arbitrary-arithmetic,
arbitrary-integer, signed-or-unsigned, cv-unqualified-arithmetic,
common-big-int-type, and common-big-int-type-with) are exposition-only
concepts and helper aliases used to constrain the interface.
common-big-int-type<L, R> denotes the basic_big_int specialization shared
by L and R when one operand is a basic_big_int and the other is either the
same specialization or a built-in signed or unsigned integer type.
template <std::size_t min_inplace_bits, class Allocator = std::allocator<uint_multiprecision_t>>
class basic_big_int {
public:
// member types
using allocator_type = Allocator;
using size_type = std::size_t;
using pointer = std::allocator_traits<Allocator>::pointer;
using const_pointer = std::allocator_traits<Allocator>::const_pointer;
// member constants
static constexpr size_type inplace_capacity = /* number of in-place limbs */;
static constexpr size_type inplace_bits =
inplace_capacity * std::numeric_limits<uint_multiprecision_t>::digits;
// [big.int.cons], construct/copy/destroy
constexpr basic_big_int() noexcept(noexcept(Allocator()));
constexpr explicit basic_big_int(const Allocator& a) noexcept;
constexpr basic_big_int(const basic_big_int& x);
constexpr basic_big_int(basic_big_int&& x) noexcept;
template <_arbitrary-arithmetic_ T>
requires(!std::same_as<std::remove_cvref_t<T>, basic_big_int>)
constexpr explicit(/* see below */) basic_big_int(T&& value) noexcept(/* see below */);
template <_arbitrary-arithmetic_ T>
constexpr basic_big_int(const T& value, const allocator_type& a) noexcept(/* see below */);
template <std::input_iterator I, std::sentinel_for<I> S>
requires _signed-or-unsigned_<std::iter_value_t<I>>
constexpr basic_big_int(I begin, S end, const allocator_type& a = allocator_type());
template <std::ranges::input_range R>
requires _signed-or-unsigned_<std::ranges::range_value_t<R>>
constexpr explicit basic_big_int(std::from_range_t, R&& r, const allocator_type& a = allocator_type());
constexpr ~basic_big_int();
// [big.int.modifiers], assignment
constexpr basic_big_int& operator=(const basic_big_int& x);
constexpr basic_big_int& operator=(basic_big_int&& x) noexcept;
template <_arbitrary-integer_ T>
requires(!std::same_as<std::remove_cvref_t<T>, basic_big_int>)
constexpr basic_big_int& operator=(T&& x) noexcept(/* see below */);
template <class T> constexpr basic_big_int& operator+=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator-=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator*=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator/=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator%=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator&=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator|=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator^=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <_signed-or-unsigned_ S> constexpr basic_big_int& operator<<=(S s);
template <_signed-or-unsigned_ S> constexpr basic_big_int& operator>>=(S s);
// [big.int.modifiers], swap
constexpr void swap(basic_big_int& x) noexcept(
std::allocator_traits<allocator_type>::propagate_on_container_swap::value ||
std::allocator_traits<allocator_type>::is_always_equal::value);
// [big.int.ops], observers
constexpr size_type width_mag() const noexcept;
constexpr std::span<const uint_multiprecision_t> representation() const noexcept;
constexpr size_type representation_size() const noexcept;
constexpr allocator_type get_allocator() const noexcept;
constexpr size_type size() const noexcept;
static constexpr size_type max_size() noexcept;
static constexpr size_type max_representation_size() noexcept;
constexpr void reserve(size_type n);
constexpr void reserve_representation(size_type n);
constexpr size_type capacity() const noexcept;
constexpr size_type representation_capacity() const noexcept;
constexpr void shrink_to_fit();
// [big.int.unary], unary operators
constexpr basic_big_int operator+() const&;
constexpr basic_big_int operator+() && noexcept;
constexpr basic_big_int operator-() const&;
constexpr basic_big_int operator-() && noexcept;
constexpr basic_big_int operator~() const&;
constexpr basic_big_int operator~() &&;
constexpr basic_big_int& operator++() &;
constexpr basic_big_int operator++(int) &;
constexpr basic_big_int& operator--() &;
constexpr basic_big_int operator--(int) &;
// [big.int.conv], conversion
template <_cv-unqualified-arithmetic_ T>
constexpr explicit operator T() const noexcept;
};
// [big.int.cmp], comparison operators
template <class L, _common-big-int-type-with_<L> R>
constexpr bool operator==(const L& lhs, const R& rhs) noexcept;
template <class L, _common-big-int-type-with_<L> R>
constexpr std::strong_ordering operator<=>(const L& lhs, const R& rhs) noexcept;
// [big.int.binary], binary operators
template <class L, class R> constexpr _common-big-int-type_<L, R> operator+(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator-(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator*(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator/(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator%(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator&(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator|(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator^(L&& x, R&& y);
template <class T, _signed-or-unsigned_ S>
requires /* remove_cvref_t<T> is a basic_big_int specialization */
constexpr std::remove_cvref_t<T> operator<<(T&& x, S s);
template <class T, _signed-or-unsigned_ S>
requires /* remove_cvref_t<T> is a basic_big_int specialization */
constexpr std::remove_cvref_t<T> operator>>(T&& x, S s);
Member types and constants
| Name | Description |
|---|---|
|
The allocator type |
|
|
|
|
|
|
|
The number of |
|
|
Constructors and destructor
Default constructor
constexpr basic_big_int() noexcept(noexcept(Allocator()));
Initializes the integer value to zero and default-constructs the allocator.
-
Preconditions: None.
-
Postconditions: None.
Allocator constructor
constexpr explicit basic_big_int(const Allocator& a) noexcept;
Initializes the integer value to zero and initializes the allocator to a.
-
Preconditions: None.
-
Postconditions: None.
Copy constructor
constexpr basic_big_int(const basic_big_int& x);
Initializes the integer value to that of x and initializes the allocator to
x.get_allocator().
-
Preconditions: None.
-
Postconditions: None.
-
Throws: Nothing if the effective width of the integer value of
xis less than or equal toinplace_bits; otherwise, any exception thrown during allocation.
Move constructor
constexpr basic_big_int(basic_big_int&& x) noexcept;
Initializes the integer value to that of x and initializes the allocator by
moving from x.get_allocator().
-
Preconditions: None.
-
Postconditions:
xis left in a valid state with an unspecified value.
Converting constructor from an arithmetic type
template <_arbitrary-arithmetic_ T>
requires(!std::same_as<std::remove_cvref_t<T>, basic_big_int>)
constexpr explicit(/* see below */) basic_big_int(T&& value) noexcept(/* see below */);
Initializes the integer value from value. If std::remove_cvref_t<T> is an
integral type or a basic_big_int specialization, the integer value is that of
value. If it is a floating-point type, the integer value is that obtained by
discarding the fractional part of value (truncation toward zero).
-
Constraints:
std::remove_cvref_t<T>is notbasic_big_int, and is a built-in integer type, a floating-point type, or abasic_big_intspecialization. -
Preconditions: If
std::remove_cvref_t<T>is a floating-point type,valueis finite. -
Postconditions: None.
-
Throws: Nothing if the effective width of the resulting value is less than or equal to
inplace_bits; otherwise, any exception thrown during allocation. -
Remarks: The constructor is
explicitunlessstd::remove_cvref_t<T>is a built-in signed or unsigned integer type or the samebasic_big_intspecialization. The expression insidenoexceptistruewhenvalueis an integral type whose width does not exceedinplace_bits.
Converting constructor from an arithmetic type with an allocator
template <_arbitrary-arithmetic_ T>
constexpr basic_big_int(const T& value, const allocator_type& a) noexcept(/* see below */);
Equivalent to the converting constructor above, but initializes the allocator to
a.
-
Preconditions: If
std::remove_cvref_t<T>is a floating-point type,valueis finite. -
Postconditions: None.
-
Throws: Nothing if the effective width of the resulting value is less than or equal to
inplace_bits; otherwise, any exception thrown during allocation.
Iterator-pair constructor
template <std::input_iterator I, std::sentinel_for<I> S>
requires _signed-or-unsigned_<std::iter_value_t<I>>
constexpr basic_big_int(I begin, S end, const allocator_type& a = allocator_type());
Initializes the integer value by concatenating the base-2 representation of each
element in [begin, end), where the first element holds the least significant
limb. If the iterator’s value type is signed, the combined representation is
interpreted as a signed integer; otherwise it is interpreted as an unsigned
integer. Initializes the allocator to a.
-
Preconditions:
[begin, end)is a valid range. -
Postconditions: None.
from_range constructor
template <std::ranges::input_range R>
requires _signed-or-unsigned_<std::ranges::range_value_t<R>>
constexpr explicit basic_big_int(std::from_range_t, R&& r, const allocator_type& a = allocator_type());
Initializes the integer value by concatenating the base-2 representation of each
element in r, where the first element holds the least significant limb. If the
range’s value type is signed, the combined representation is interpreted as a
signed integer; otherwise it is interpreted as an unsigned integer. Initializes
the allocator to a.
-
Preconditions: None.
-
Postconditions: None.
This constructor is available when the standard library provides
<ranges> container support (the __cpp_lib_containers_ranges feature-test macro).
|
Assignment
Copy assignment
constexpr basic_big_int& operator=(const basic_big_int& x);
Sets the integer value to that of x and returns *this.
-
Preconditions: None.
-
Postconditions: None.
Move assignment
constexpr basic_big_int& operator=(basic_big_int&& x) noexcept;
Sets the integer value to that of x and returns *this.
-
Preconditions: None.
-
Postconditions:
xis left in a valid state with an unspecified value.
Assignment from an integer type
template <_arbitrary-integer_ T>
requires(!std::same_as<std::remove_cvref_t<T>, basic_big_int>)
constexpr basic_big_int& operator=(T&& x) noexcept(/* see below */);
Sets the integer value to that of x and returns *this. Note that, unlike the
converting constructor, this operator does not accept floating-point operands.
-
Constraints:
std::remove_cvref_t<T>is notbasic_big_int, and is a built-in integer type or abasic_big_intspecialization. -
Preconditions: None.
-
Postconditions: None.
-
Remarks: The expression inside
noexceptistruewhenxis an integral type whose width does not exceedinplace_bits.
Compound assignment operators
Arithmetic and bitwise compound assignment
template <class T> constexpr basic_big_int& operator+=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator-=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator*=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator&=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator|=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator^=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
Each operator @= is equivalent to *this = std::move(*this) @ std::forward<T>(rhs)
and returns *this, where @ is the corresponding binary operator.
-
Preconditions: None.
-
Postconditions: None.
Division and remainder compound assignment
template <class T> constexpr basic_big_int& operator/=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
template <class T> constexpr basic_big_int& operator%=(T&& rhs) requires _common-big-int-type-with_<T, basic_big_int>;
operator/= sets *this to the quotient and operator%= sets *this to the
remainder of dividing *this by rhs, truncating toward zero, and returns
*this.
-
Preconditions: The integer value of
rhsis nonzero. -
Postconditions: None.
Shift compound assignment
template <_signed-or-unsigned_ S> constexpr basic_big_int& operator<<=(S s);
template <_signed-or-unsigned_ S> constexpr basic_big_int& operator>>=(S s);
operator<⇐ is equivalent to *this = std::move(*this) << s (multiplication by
2^s); operator>>= is equivalent to *this = std::move(*this) >> s (division
by 2^s, rounded toward negative infinity). Each returns *this.
-
Preconditions:
s >= 0, andsdoes not exceed the maximum shiftmax_size(). -
Postconditions: None.
Swap
constexpr void swap(basic_big_int& x) noexcept(
std::allocator_traits<allocator_type>::propagate_on_container_swap::value ||
std::allocator_traits<allocator_type>::is_always_equal::value);
Exchanges the integer values of *this and x. Any dynamically-allocated
storage is exchanged directly rather than reallocated, so the operation neither
allocates nor deallocates. If
std::allocator_traits<allocator_type>::propagate_on_container_swap::value is
true, the allocators are also exchanged using an unqualified call to swap;
otherwise they are left unchanged.
-
Preconditions:
std::allocator_traits<allocator_type>::propagate_on_container_swap::valueistrue, orget_allocator() == x.get_allocator(). -
Postconditions:
*thisholds the integer value thatxheld before the call, andxholds the integer value that*thisheld before the call. The allocators are exchanged if and only ifstd::allocator_traits<allocator_type>::propagate_on_container_swap::valueistrue. -
Throws: Nothing.
Observers
Throughout this section, a "limb" is one uint_multiprecision_t object of the
magnitude’s little-endian representation.
representation
constexpr std::span<const uint_multiprecision_t> representation() const noexcept;
Returns a std::span over the limbs that make up the magnitude, whether stored
in place or in dynamic storage. The first limb in the range holds the least
significant bits.
-
Preconditions: None.
-
Postconditions: None.
-
Remarks: If the integer value is greater than or equal to zero,
basic_big_int(std::from_range, representation(), get_allocator())has the same integer value.
representation_size
constexpr size_type representation_size() const noexcept;
Returns the number of limbs that make up the magnitude: 1 if the integer value
is zero, and otherwise ceil(size() / std::numeric_limits<uint_multiprecision_t>::digits).
This is the size of the span returned by representation().
-
Preconditions: None.
-
Postconditions: None.
width_mag
constexpr size_type width_mag() const noexcept;
Returns the number of significant bits in the magnitude of the value (ignoring
the sign), or 0 if the magnitude is zero.
-
Preconditions: None.
-
Postconditions: None.
get_allocator
constexpr allocator_type get_allocator() const noexcept;
Returns a copy of the object’s allocator.
-
Preconditions: None.
-
Postconditions: None.
size
constexpr size_type size() const noexcept;
Returns the number of bits required to represent the magnitude of the value:
0 if the integer value is zero, and otherwise floor(log2(|v|)) + 1, where
v is the integer value.
-
Preconditions: None.
-
Postconditions: None.
max_size
static constexpr size_type max_size() noexcept;
Returns the maximum number of bits that the magnitude may occupy, that is,
max_representation_size() * std::numeric_limits<uint_multiprecision_t>::digits.
-
Preconditions: None.
-
Postconditions: None.
max_representation_size
static constexpr size_type max_representation_size() noexcept;
Returns the maximum number of limbs that can be part of the representation, that
is, max_size() / std::numeric_limits<uint_multiprecision_t>::digits.
-
Preconditions: None.
-
Postconditions: None.
reserve
constexpr void reserve(size_type n);
A directive, expressed as a number of bits, that informs the object of a planned
increase in size so that storage can be allocated up front. The bit count is
rounded up to a whole number of limbs; equivalent to
reserve_representation(ceil(n / std::numeric_limits<uint_multiprecision_t>::digits)).
-
Preconditions: None.
-
Postconditions: If reallocation occurs,
capacity()is greater than or equal ton; otherwise,capacity()is unchanged.
reserve_representation
constexpr void reserve_representation(size_type n);
A directive that informs the object of a planned increase in size, expressed as a
number of limbs, so that storage can be allocated up front. Equivalent to
reserve(n * std::numeric_limits<uint_multiprecision_t>::digits).
-
Preconditions: None.
-
Postconditions: If reallocation occurs,
representation_capacity()is greater than or equal ton; otherwise, the capacity is unchanged.
capacity
constexpr size_type capacity() const noexcept;
Returns the number of bits of storage currently available without reallocating,
that is, representation_capacity() * std::numeric_limits<uint_multiprecision_t>::digits.
While the value is held in the in-place (small-object) storage this equals
inplace_bits.
-
Preconditions: None.
-
Postconditions: None.
representation_capacity
constexpr size_type representation_capacity() const noexcept;
Returns the number of limbs that can be held without allocating: the greater of
inplace_capacity and the number of limbs of dynamically-allocated storage
currently available. Unlike capacity(), which is expressed in bits, this is a
limb count that never reports fewer than inplace_capacity limbs.
-
Preconditions: None.
-
Postconditions: None.
shrink_to_fit
constexpr void shrink_to_fit();
If the magnitude fits in the in-place storage, frees any dynamic allocation and
moves the value into the in-place storage. Otherwise, this is a non-binding
request to reduce the dynamic capacity to the number of limbs in use; it never
increases capacity(), but may reduce it, which can cause a reallocation.
-
Preconditions: None.
-
Postconditions: None.
Unary operators
operator+
constexpr basic_big_int operator+() const&;
constexpr basic_big_int operator+() && noexcept;
Returns a copy of *this (for the lvalue overload) or std::move(*this) (for
the rvalue overload). The value is unchanged.
-
Preconditions: None.
-
Postconditions: None.
operator-
constexpr basic_big_int operator-() const&;
constexpr basic_big_int operator-() && noexcept;
Returns the arithmetic negation of the value (equivalent to 0 - *this). The
rvalue overload reuses the operand’s storage and only flips the sign.
-
Preconditions: None.
-
Postconditions: None.
operator~
constexpr basic_big_int operator~() const&;
constexpr basic_big_int operator~() &&;
Returns the bitwise complement of the value as if performed on an
infinite-width two’s-complement representation (equivalent to -1 - *this).
-
Preconditions: None.
-
Postconditions: None.
operator++
constexpr basic_big_int& operator++() &; // pre-increment
constexpr basic_big_int operator++(int) &; // post-increment
Pre-increment is equivalent to *this += 1 and returns *this. Post-increment
increments *this and returns a copy of the value prior to the increment.
-
Preconditions: None.
-
Postconditions: None.
operator--
constexpr basic_big_int& operator--() &; // pre-decrement
constexpr basic_big_int operator--(int) &; // post-decrement
Pre-decrement is equivalent to *this -= 1 and returns *this. Post-decrement
decrements *this and returns a copy of the value prior to the decrement.
-
Preconditions: None.
-
Postconditions: None.
Conversion operator
template <_cv-unqualified-arithmetic_ T>
constexpr explicit operator T() const noexcept;
Converts the value to T. The result is static_cast<T>(static_cast<U>(v)),
where v is the integer value and U is a hypothetical signed integer type
wide enough to represent v. If T is bool, the result is true when the
value is nonzero and false otherwise. If T is a floating-point type, the
result is determined as if by a floating-integral conversion.
-
Constraints:
Tis a cv-unqualified arithmetic type. -
Preconditions: None.
-
Postconditions: None.
Comparison operators
template <class L, _common-big-int-type-with_<L> R>
constexpr bool operator==(const L& lhs, const R& rhs) noexcept;
template <class L, _common-big-int-type-with_<L> R>
constexpr std::strong_ordering operator<=>(const L& lhs, const R& rhs) noexcept;
operator== returns true if the integer value of lhs equals the integer
value of rhs. operator<⇒ returns std::strong_ordering::less,
std::strong_ordering::greater, or std::strong_ordering::equal according to
whether the integer value of lhs is less than, greater than, or equal to the
integer value of rhs. At least one operand is a basic_big_int; the other may
be the same basic_big_int specialization or a built-in signed or unsigned
integer type.
-
Preconditions: None.
-
Postconditions: None.
Binary operators
Arithmetic and bitwise operators
template <class L, class R> constexpr _common-big-int-type_<L, R> operator+(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator-(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator*(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator&(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator|(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator^(L&& x, R&& y);
Each returns a basic_big_int whose integer value is T(x) @ T(y), where @
is the corresponding operator and T is a hypothetical signed integer type with
infinite range. One operand is a basic_big_int and the other is the same
specialization or a built-in signed or unsigned integer type.
-
Preconditions: None.
-
Postconditions: None.
-
Remarks: The bitwise operators (
&,|,^) behave as if performed on a two’s-complement representation in which non-negative numbers have infinitely many leading zero bits and negative numbers have infinitely many leading one bits.
Division and remainder operators
template <class L, class R> constexpr _common-big-int-type_<L, R> operator/(L&& x, R&& y);
template <class L, class R> constexpr _common-big-int-type_<L, R> operator%(L&& x, R&& y);
operator/ returns the quotient and operator% returns the remainder of
dividing x by y, truncating toward zero (matching the behavior of the
built-in integer types).
-
Preconditions: The integer value of
yis nonzero. -
Postconditions: None.
Shift operators
template <class T, _signed-or-unsigned_ S>
requires /* remove_cvref_t<T> is a basic_big_int specialization */
constexpr std::remove_cvref_t<T> operator<<(T&& x, S s);
template <class T, _signed-or-unsigned_ S>
requires /* remove_cvref_t<T> is a basic_big_int specialization */
constexpr std::remove_cvref_t<T> operator>>(T&& x, S s);
operator<< returns a basic_big_int whose integer value is v * 2^s, and
operator>> returns one whose integer value is v / 2^s rounded toward
negative infinity, where v is the integer value of x. The result uses the
allocator of x.
-
Constraints:
std::remove_cvref_t<T>is abasic_big_intspecialization. -
Preconditions:
s >= 0, andsdoes not exceed the maximum shift for the result type (max_size()). -
Postconditions: None.