109efe848SGuillaume Chatelet //===-- A class to manipulate wide integers. --------------------*- C++ -*-===// 209efe848SGuillaume Chatelet // 309efe848SGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 409efe848SGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information. 509efe848SGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 609efe848SGuillaume Chatelet // 709efe848SGuillaume Chatelet //===----------------------------------------------------------------------===// 809efe848SGuillaume Chatelet 921895a84SOleksandr T. #ifndef LLVM_LIBC_SRC___SUPPORT_BIG_INT_H 1021895a84SOleksandr T. #define LLVM_LIBC_SRC___SUPPORT_BIG_INT_H 1109efe848SGuillaume Chatelet 1209efe848SGuillaume Chatelet #include "src/__support/CPP/array.h" 1309efe848SGuillaume Chatelet #include "src/__support/CPP/bit.h" // countl_zero 1409efe848SGuillaume Chatelet #include "src/__support/CPP/limits.h" 1509efe848SGuillaume Chatelet #include "src/__support/CPP/optional.h" 1609efe848SGuillaume Chatelet #include "src/__support/CPP/type_traits.h" 1709efe848SGuillaume Chatelet #include "src/__support/macros/attributes.h" // LIBC_INLINE 185ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 1909efe848SGuillaume Chatelet #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY 2009efe848SGuillaume Chatelet #include "src/__support/macros/properties/compiler.h" // LIBC_COMPILER_IS_CLANG 2109efe848SGuillaume Chatelet #include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128, LIBC_TYPES_HAS_INT64 2209efe848SGuillaume Chatelet #include "src/__support/math_extras.h" // add_with_carry, sub_with_borrow 2309efe848SGuillaume Chatelet #include "src/__support/number_pair.h" 2409efe848SGuillaume Chatelet 2509efe848SGuillaume Chatelet #include <stddef.h> // For size_t 2609efe848SGuillaume Chatelet #include <stdint.h> 2709efe848SGuillaume Chatelet 285ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 2909efe848SGuillaume Chatelet 3009efe848SGuillaume Chatelet namespace multiword { 3109efe848SGuillaume Chatelet 3209efe848SGuillaume Chatelet // A type trait mapping unsigned integers to their half-width unsigned 3309efe848SGuillaume Chatelet // counterparts. 3409efe848SGuillaume Chatelet template <typename T> struct half_width; 3509efe848SGuillaume Chatelet template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {}; 3609efe848SGuillaume Chatelet template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {}; 3709efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT64 3809efe848SGuillaume Chatelet template <> struct half_width<uint64_t> : cpp::type_identity<uint32_t> {}; 3909efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT128 4009efe848SGuillaume Chatelet template <> struct half_width<__uint128_t> : cpp::type_identity<uint64_t> {}; 4109efe848SGuillaume Chatelet #endif // LIBC_TYPES_HAS_INT128 4209efe848SGuillaume Chatelet #endif // LIBC_TYPES_HAS_INT64 4309efe848SGuillaume Chatelet template <typename T> using half_width_t = typename half_width<T>::type; 4409efe848SGuillaume Chatelet 4509efe848SGuillaume Chatelet // An array of two elements that can be used in multiword operations. 4609efe848SGuillaume Chatelet template <typename T> struct DoubleWide final : cpp::array<T, 2> { 4709efe848SGuillaume Chatelet using UP = cpp::array<T, 2>; 4809efe848SGuillaume Chatelet using UP::UP; 4909efe848SGuillaume Chatelet LIBC_INLINE constexpr DoubleWide(T lo, T hi) : UP({lo, hi}) {} 5009efe848SGuillaume Chatelet }; 5109efe848SGuillaume Chatelet 5209efe848SGuillaume Chatelet // Converts an unsigned value into a DoubleWide<half_width_t<T>>. 5309efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr auto split(T value) { 5409efe848SGuillaume Chatelet static_assert(cpp::is_unsigned_v<T>); 5509efe848SGuillaume Chatelet using half_type = half_width_t<T>; 5609efe848SGuillaume Chatelet return DoubleWide<half_type>( 5709efe848SGuillaume Chatelet half_type(value), 5809efe848SGuillaume Chatelet half_type(value >> cpp::numeric_limits<half_type>::digits)); 5909efe848SGuillaume Chatelet } 6009efe848SGuillaume Chatelet 6109efe848SGuillaume Chatelet // The low part of a DoubleWide value. 6209efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr T lo(const DoubleWide<T> &value) { 6309efe848SGuillaume Chatelet return value[0]; 6409efe848SGuillaume Chatelet } 6509efe848SGuillaume Chatelet // The high part of a DoubleWide value. 6609efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr T hi(const DoubleWide<T> &value) { 6709efe848SGuillaume Chatelet return value[1]; 6809efe848SGuillaume Chatelet } 6909efe848SGuillaume Chatelet // The low part of an unsigned value. 7009efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr half_width_t<T> lo(T value) { 7109efe848SGuillaume Chatelet return lo(split(value)); 7209efe848SGuillaume Chatelet } 7309efe848SGuillaume Chatelet // The high part of an unsigned value. 7409efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr half_width_t<T> hi(T value) { 7509efe848SGuillaume Chatelet return hi(split(value)); 7609efe848SGuillaume Chatelet } 7709efe848SGuillaume Chatelet 7809efe848SGuillaume Chatelet // Returns 'a' times 'b' in a DoubleWide<word>. Cannot overflow by construction. 7909efe848SGuillaume Chatelet template <typename word> 8009efe848SGuillaume Chatelet LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) { 8109efe848SGuillaume Chatelet if constexpr (cpp::is_same_v<word, uint8_t>) { 8209efe848SGuillaume Chatelet return split<uint16_t>(uint16_t(a) * uint16_t(b)); 8309efe848SGuillaume Chatelet } else if constexpr (cpp::is_same_v<word, uint16_t>) { 8409efe848SGuillaume Chatelet return split<uint32_t>(uint32_t(a) * uint32_t(b)); 8509efe848SGuillaume Chatelet } 8609efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT64 8709efe848SGuillaume Chatelet else if constexpr (cpp::is_same_v<word, uint32_t>) { 8809efe848SGuillaume Chatelet return split<uint64_t>(uint64_t(a) * uint64_t(b)); 8909efe848SGuillaume Chatelet } 9009efe848SGuillaume Chatelet #endif 9109efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT128 9209efe848SGuillaume Chatelet else if constexpr (cpp::is_same_v<word, uint64_t>) { 9309efe848SGuillaume Chatelet return split<__uint128_t>(__uint128_t(a) * __uint128_t(b)); 9409efe848SGuillaume Chatelet } 9509efe848SGuillaume Chatelet #endif 9609efe848SGuillaume Chatelet else { 9709efe848SGuillaume Chatelet using half_word = half_width_t<word>; 9809efe848SGuillaume Chatelet const auto shiftl = [](word value) -> word { 9909efe848SGuillaume Chatelet return value << cpp::numeric_limits<half_word>::digits; 10009efe848SGuillaume Chatelet }; 10109efe848SGuillaume Chatelet const auto shiftr = [](word value) -> word { 10209efe848SGuillaume Chatelet return value >> cpp::numeric_limits<half_word>::digits; 10309efe848SGuillaume Chatelet }; 10409efe848SGuillaume Chatelet // Here we do a one digit multiplication where 'a' and 'b' are of type 10509efe848SGuillaume Chatelet // word. We split 'a' and 'b' into half words and perform the classic long 10609efe848SGuillaume Chatelet // multiplication with 'a' and 'b' being two-digit numbers. 10709efe848SGuillaume Chatelet 10809efe848SGuillaume Chatelet // a a_hi a_lo 10909efe848SGuillaume Chatelet // x b => x b_hi b_lo 11009efe848SGuillaume Chatelet // ---- ----------- 11109efe848SGuillaume Chatelet // c result 11209efe848SGuillaume Chatelet // We convert 'lo' and 'hi' from 'half_word' to 'word' so multiplication 11309efe848SGuillaume Chatelet // doesn't overflow. 11409efe848SGuillaume Chatelet const word a_lo = lo(a); 11509efe848SGuillaume Chatelet const word b_lo = lo(b); 11609efe848SGuillaume Chatelet const word a_hi = hi(a); 11709efe848SGuillaume Chatelet const word b_hi = hi(b); 11809efe848SGuillaume Chatelet const word step1 = b_lo * a_lo; // no overflow; 11909efe848SGuillaume Chatelet const word step2 = b_lo * a_hi; // no overflow; 12009efe848SGuillaume Chatelet const word step3 = b_hi * a_lo; // no overflow; 12109efe848SGuillaume Chatelet const word step4 = b_hi * a_hi; // no overflow; 12209efe848SGuillaume Chatelet word lo_digit = step1; 12309efe848SGuillaume Chatelet word hi_digit = step4; 12409efe848SGuillaume Chatelet const word no_carry = 0; 12509efe848SGuillaume Chatelet word carry; 12609efe848SGuillaume Chatelet word _; // unused carry variable. 12709efe848SGuillaume Chatelet lo_digit = add_with_carry<word>(lo_digit, shiftl(step2), no_carry, carry); 12809efe848SGuillaume Chatelet hi_digit = add_with_carry<word>(hi_digit, shiftr(step2), carry, _); 12909efe848SGuillaume Chatelet lo_digit = add_with_carry<word>(lo_digit, shiftl(step3), no_carry, carry); 13009efe848SGuillaume Chatelet hi_digit = add_with_carry<word>(hi_digit, shiftr(step3), carry, _); 13109efe848SGuillaume Chatelet return DoubleWide<word>(lo_digit, hi_digit); 13209efe848SGuillaume Chatelet } 13309efe848SGuillaume Chatelet } 13409efe848SGuillaume Chatelet 13509efe848SGuillaume Chatelet // In-place 'dst op= rhs' with operation with carry propagation. Returns carry. 13609efe848SGuillaume Chatelet template <typename Function, typename word, size_t N, size_t M> 13709efe848SGuillaume Chatelet LIBC_INLINE constexpr word inplace_binop(Function op_with_carry, 13809efe848SGuillaume Chatelet cpp::array<word, N> &dst, 13909efe848SGuillaume Chatelet const cpp::array<word, M> &rhs) { 14009efe848SGuillaume Chatelet static_assert(N >= M); 14109efe848SGuillaume Chatelet word carry_out = 0; 14209efe848SGuillaume Chatelet for (size_t i = 0; i < N; ++i) { 14309efe848SGuillaume Chatelet const bool has_rhs_value = i < M; 14409efe848SGuillaume Chatelet const word rhs_value = has_rhs_value ? rhs[i] : 0; 14509efe848SGuillaume Chatelet const word carry_in = carry_out; 14609efe848SGuillaume Chatelet dst[i] = op_with_carry(dst[i], rhs_value, carry_in, carry_out); 14709efe848SGuillaume Chatelet // stop early when rhs is over and no carry is to be propagated. 14809efe848SGuillaume Chatelet if (!has_rhs_value && carry_out == 0) 14909efe848SGuillaume Chatelet break; 15009efe848SGuillaume Chatelet } 15109efe848SGuillaume Chatelet return carry_out; 15209efe848SGuillaume Chatelet } 15309efe848SGuillaume Chatelet 15409efe848SGuillaume Chatelet // In-place addition. Returns carry. 15509efe848SGuillaume Chatelet template <typename word, size_t N, size_t M> 15609efe848SGuillaume Chatelet LIBC_INLINE constexpr word add_with_carry(cpp::array<word, N> &dst, 15709efe848SGuillaume Chatelet const cpp::array<word, M> &rhs) { 15809efe848SGuillaume Chatelet return inplace_binop(LIBC_NAMESPACE::add_with_carry<word>, dst, rhs); 15909efe848SGuillaume Chatelet } 16009efe848SGuillaume Chatelet 16109efe848SGuillaume Chatelet // In-place subtraction. Returns borrow. 16209efe848SGuillaume Chatelet template <typename word, size_t N, size_t M> 16309efe848SGuillaume Chatelet LIBC_INLINE constexpr word sub_with_borrow(cpp::array<word, N> &dst, 16409efe848SGuillaume Chatelet const cpp::array<word, M> &rhs) { 16509efe848SGuillaume Chatelet return inplace_binop(LIBC_NAMESPACE::sub_with_borrow<word>, dst, rhs); 16609efe848SGuillaume Chatelet } 16709efe848SGuillaume Chatelet 16809efe848SGuillaume Chatelet // In-place multiply-add. Returns carry. 16909efe848SGuillaume Chatelet // i.e., 'dst += b * c' 17009efe848SGuillaume Chatelet template <typename word, size_t N> 17109efe848SGuillaume Chatelet LIBC_INLINE constexpr word mul_add_with_carry(cpp::array<word, N> &dst, word b, 17209efe848SGuillaume Chatelet word c) { 17309efe848SGuillaume Chatelet return add_with_carry(dst, mul2(b, c)); 17409efe848SGuillaume Chatelet } 17509efe848SGuillaume Chatelet 17609efe848SGuillaume Chatelet // An array of two elements serving as an accumulator during multiword 17709efe848SGuillaume Chatelet // computations. 17809efe848SGuillaume Chatelet template <typename T> struct Accumulator final : cpp::array<T, 2> { 17909efe848SGuillaume Chatelet using UP = cpp::array<T, 2>; 18009efe848SGuillaume Chatelet LIBC_INLINE constexpr Accumulator() : UP({0, 0}) {} 18109efe848SGuillaume Chatelet LIBC_INLINE constexpr T advance(T carry_in) { 18209efe848SGuillaume Chatelet auto result = UP::front(); 18309efe848SGuillaume Chatelet UP::front() = UP::back(); 18409efe848SGuillaume Chatelet UP::back() = carry_in; 18509efe848SGuillaume Chatelet return result; 18609efe848SGuillaume Chatelet } 18709efe848SGuillaume Chatelet LIBC_INLINE constexpr T sum() const { return UP::front(); } 18809efe848SGuillaume Chatelet LIBC_INLINE constexpr T carry() const { return UP::back(); } 18909efe848SGuillaume Chatelet }; 19009efe848SGuillaume Chatelet 19109efe848SGuillaume Chatelet // In-place multiplication by a single word. Returns carry. 19209efe848SGuillaume Chatelet template <typename word, size_t N> 19309efe848SGuillaume Chatelet LIBC_INLINE constexpr word scalar_multiply_with_carry(cpp::array<word, N> &dst, 19409efe848SGuillaume Chatelet word x) { 19509efe848SGuillaume Chatelet Accumulator<word> acc; 19609efe848SGuillaume Chatelet for (auto &val : dst) { 19709efe848SGuillaume Chatelet const word carry = mul_add_with_carry(acc, val, x); 19809efe848SGuillaume Chatelet val = acc.advance(carry); 19909efe848SGuillaume Chatelet } 20009efe848SGuillaume Chatelet return acc.carry(); 20109efe848SGuillaume Chatelet } 20209efe848SGuillaume Chatelet 20309efe848SGuillaume Chatelet // Multiplication of 'lhs' by 'rhs' into 'dst'. Returns carry. 20409efe848SGuillaume Chatelet // This function is safe to use for signed numbers. 20509efe848SGuillaume Chatelet // https://stackoverflow.com/a/20793834 20609efe848SGuillaume Chatelet // https://pages.cs.wisc.edu/%7Emarkhill/cs354/Fall2008/beyond354/int.mult.html 20709efe848SGuillaume Chatelet template <typename word, size_t O, size_t M, size_t N> 20809efe848SGuillaume Chatelet LIBC_INLINE constexpr word multiply_with_carry(cpp::array<word, O> &dst, 20909efe848SGuillaume Chatelet const cpp::array<word, M> &lhs, 21009efe848SGuillaume Chatelet const cpp::array<word, N> &rhs) { 21109efe848SGuillaume Chatelet static_assert(O >= M + N); 21209efe848SGuillaume Chatelet Accumulator<word> acc; 21309efe848SGuillaume Chatelet for (size_t i = 0; i < O; ++i) { 21409efe848SGuillaume Chatelet const size_t lower_idx = i < N ? 0 : i - N + 1; 21509efe848SGuillaume Chatelet const size_t upper_idx = i < M ? i : M - 1; 21609efe848SGuillaume Chatelet word carry = 0; 21709efe848SGuillaume Chatelet for (size_t j = lower_idx; j <= upper_idx; ++j) 21809efe848SGuillaume Chatelet carry += mul_add_with_carry(acc, lhs[j], rhs[i - j]); 21909efe848SGuillaume Chatelet dst[i] = acc.advance(carry); 22009efe848SGuillaume Chatelet } 22109efe848SGuillaume Chatelet return acc.carry(); 22209efe848SGuillaume Chatelet } 22309efe848SGuillaume Chatelet 22409efe848SGuillaume Chatelet template <typename word, size_t N> 22509efe848SGuillaume Chatelet LIBC_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst, 22609efe848SGuillaume Chatelet const cpp::array<word, N> &lhs, 22709efe848SGuillaume Chatelet const cpp::array<word, N> &rhs) { 22809efe848SGuillaume Chatelet Accumulator<word> acc; 22909efe848SGuillaume Chatelet word carry = 0; 23009efe848SGuillaume Chatelet // First round of accumulation for those at N - 1 in the full product. 23109efe848SGuillaume Chatelet for (size_t i = 0; i < N; ++i) 23209efe848SGuillaume Chatelet carry += mul_add_with_carry(acc, lhs[i], rhs[N - 1 - i]); 23309efe848SGuillaume Chatelet for (size_t i = N; i < 2 * N - 1; ++i) { 23409efe848SGuillaume Chatelet acc.advance(carry); 23509efe848SGuillaume Chatelet carry = 0; 23609efe848SGuillaume Chatelet for (size_t j = i - N + 1; j < N; ++j) 23709efe848SGuillaume Chatelet carry += mul_add_with_carry(acc, lhs[j], rhs[i - j]); 23809efe848SGuillaume Chatelet dst[i - N] = acc.sum(); 23909efe848SGuillaume Chatelet } 24009efe848SGuillaume Chatelet dst.back() = acc.carry(); 24109efe848SGuillaume Chatelet } 24209efe848SGuillaume Chatelet 24309efe848SGuillaume Chatelet template <typename word, size_t N> 24409efe848SGuillaume Chatelet LIBC_INLINE constexpr bool is_negative(cpp::array<word, N> &array) { 24509efe848SGuillaume Chatelet using signed_word = cpp::make_signed_t<word>; 24609efe848SGuillaume Chatelet return cpp::bit_cast<signed_word>(array.back()) < 0; 24709efe848SGuillaume Chatelet } 24809efe848SGuillaume Chatelet 24909efe848SGuillaume Chatelet // An enum for the shift function below. 25009efe848SGuillaume Chatelet enum Direction { LEFT, RIGHT }; 25109efe848SGuillaume Chatelet 25209efe848SGuillaume Chatelet // A bitwise shift on an array of elements. 253b88a1dd6SGuillaume Chatelet // 'offset' must be less than TOTAL_BITS (i.e., sizeof(word) * CHAR_BIT * N) 254b88a1dd6SGuillaume Chatelet // otherwise the behavior is undefined. 25509efe848SGuillaume Chatelet template <Direction direction, bool is_signed, typename word, size_t N> 25609efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array, 25709efe848SGuillaume Chatelet size_t offset) { 25809efe848SGuillaume Chatelet static_assert(direction == LEFT || direction == RIGHT); 25909efe848SGuillaume Chatelet constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits; 26009efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT128 261bd589f5cSGuillaume Chatelet constexpr size_t TOTAL_BITS = N * WORD_BITS; 26209efe848SGuillaume Chatelet if constexpr (TOTAL_BITS == 128) { 26309efe848SGuillaume Chatelet using type = cpp::conditional_t<is_signed, __int128_t, __uint128_t>; 26409efe848SGuillaume Chatelet auto tmp = cpp::bit_cast<type>(array); 26509efe848SGuillaume Chatelet if constexpr (direction == LEFT) 26609efe848SGuillaume Chatelet tmp <<= offset; 26709efe848SGuillaume Chatelet else 26809efe848SGuillaume Chatelet tmp >>= offset; 26909efe848SGuillaume Chatelet return cpp::bit_cast<cpp::array<word, N>>(tmp); 27009efe848SGuillaume Chatelet } 27109efe848SGuillaume Chatelet #endif 272b88a1dd6SGuillaume Chatelet if (LIBC_UNLIKELY(offset == 0)) 273b88a1dd6SGuillaume Chatelet return array; 27409efe848SGuillaume Chatelet const bool is_neg = is_signed && is_negative(array); 27509efe848SGuillaume Chatelet constexpr auto at = [](size_t index) -> int { 27609efe848SGuillaume Chatelet // reverse iteration when direction == LEFT. 27709efe848SGuillaume Chatelet if constexpr (direction == LEFT) 27809efe848SGuillaume Chatelet return int(N) - int(index) - 1; 27909efe848SGuillaume Chatelet return int(index); 28009efe848SGuillaume Chatelet }; 28109efe848SGuillaume Chatelet const auto safe_get_at = [&](size_t index) -> word { 28209efe848SGuillaume Chatelet // return appropriate value when accessing out of bound elements. 28309efe848SGuillaume Chatelet const int i = at(index); 28409efe848SGuillaume Chatelet if (i < 0) 28509efe848SGuillaume Chatelet return 0; 28609efe848SGuillaume Chatelet if (i >= int(N)) 28709efe848SGuillaume Chatelet return is_neg ? -1 : 0; 28809efe848SGuillaume Chatelet return array[i]; 28909efe848SGuillaume Chatelet }; 29009efe848SGuillaume Chatelet const size_t index_offset = offset / WORD_BITS; 29109efe848SGuillaume Chatelet const size_t bit_offset = offset % WORD_BITS; 29209efe848SGuillaume Chatelet #ifdef LIBC_COMPILER_IS_CLANG 29309efe848SGuillaume Chatelet __builtin_assume(index_offset < N); 29409efe848SGuillaume Chatelet #endif 29509efe848SGuillaume Chatelet cpp::array<word, N> out = {}; 29609efe848SGuillaume Chatelet for (size_t index = 0; index < N; ++index) { 29709efe848SGuillaume Chatelet const word part1 = safe_get_at(index + index_offset); 29809efe848SGuillaume Chatelet const word part2 = safe_get_at(index + index_offset + 1); 29909efe848SGuillaume Chatelet word &dst = out[at(index)]; 30009efe848SGuillaume Chatelet if (bit_offset == 0) 30109efe848SGuillaume Chatelet dst = part1; // no crosstalk between parts. 30209efe848SGuillaume Chatelet else if constexpr (direction == LEFT) 3036b21e170SOverMighty dst = static_cast<word>((part1 << bit_offset) | 3046b21e170SOverMighty (part2 >> (WORD_BITS - bit_offset))); 30509efe848SGuillaume Chatelet else 306b5efd214SOverMighty dst = static_cast<word>((part1 >> bit_offset) | 307b5efd214SOverMighty (part2 << (WORD_BITS - bit_offset))); 30809efe848SGuillaume Chatelet } 30909efe848SGuillaume Chatelet return out; 31009efe848SGuillaume Chatelet } 31109efe848SGuillaume Chatelet 31209efe848SGuillaume Chatelet #define DECLARE_COUNTBIT(NAME, INDEX_EXPR) \ 31309efe848SGuillaume Chatelet template <typename word, size_t N> \ 31409efe848SGuillaume Chatelet LIBC_INLINE constexpr int NAME(const cpp::array<word, N> &val) { \ 31509efe848SGuillaume Chatelet int bit_count = 0; \ 31609efe848SGuillaume Chatelet for (size_t i = 0; i < N; ++i) { \ 31709efe848SGuillaume Chatelet const int word_count = cpp::NAME<word>(val[INDEX_EXPR]); \ 31809efe848SGuillaume Chatelet bit_count += word_count; \ 31909efe848SGuillaume Chatelet if (word_count != cpp::numeric_limits<word>::digits) \ 32009efe848SGuillaume Chatelet break; \ 32109efe848SGuillaume Chatelet } \ 32209efe848SGuillaume Chatelet return bit_count; \ 32309efe848SGuillaume Chatelet } 32409efe848SGuillaume Chatelet 32509efe848SGuillaume Chatelet DECLARE_COUNTBIT(countr_zero, i) // iterating forward 32609efe848SGuillaume Chatelet DECLARE_COUNTBIT(countr_one, i) // iterating forward 32709efe848SGuillaume Chatelet DECLARE_COUNTBIT(countl_zero, N - i - 1) // iterating backward 32809efe848SGuillaume Chatelet DECLARE_COUNTBIT(countl_one, N - i - 1) // iterating backward 32909efe848SGuillaume Chatelet 33009efe848SGuillaume Chatelet } // namespace multiword 33109efe848SGuillaume Chatelet 33209efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename WordType = uint64_t> 33309efe848SGuillaume Chatelet struct BigInt { 33409efe848SGuillaume Chatelet private: 33509efe848SGuillaume Chatelet static_assert(cpp::is_integral_v<WordType> && cpp::is_unsigned_v<WordType>, 33609efe848SGuillaume Chatelet "WordType must be unsigned integer."); 33709efe848SGuillaume Chatelet 33809efe848SGuillaume Chatelet struct Division { 33909efe848SGuillaume Chatelet BigInt quotient; 34009efe848SGuillaume Chatelet BigInt remainder; 34109efe848SGuillaume Chatelet }; 34209efe848SGuillaume Chatelet 34309efe848SGuillaume Chatelet public: 34409efe848SGuillaume Chatelet using word_type = WordType; 34509efe848SGuillaume Chatelet using unsigned_type = BigInt<Bits, false, word_type>; 34609efe848SGuillaume Chatelet using signed_type = BigInt<Bits, true, word_type>; 34709efe848SGuillaume Chatelet 34809efe848SGuillaume Chatelet LIBC_INLINE_VAR static constexpr bool SIGNED = Signed; 34909efe848SGuillaume Chatelet LIBC_INLINE_VAR static constexpr size_t BITS = Bits; 35009efe848SGuillaume Chatelet LIBC_INLINE_VAR 35109efe848SGuillaume Chatelet static constexpr size_t WORD_SIZE = sizeof(WordType) * CHAR_BIT; 35209efe848SGuillaume Chatelet 35309efe848SGuillaume Chatelet static_assert(Bits > 0 && Bits % WORD_SIZE == 0, 35409efe848SGuillaume Chatelet "Number of bits in BigInt should be a multiple of WORD_SIZE."); 35509efe848SGuillaume Chatelet 35609efe848SGuillaume Chatelet LIBC_INLINE_VAR static constexpr size_t WORD_COUNT = Bits / WORD_SIZE; 35709efe848SGuillaume Chatelet 35809efe848SGuillaume Chatelet cpp::array<WordType, WORD_COUNT> val{}; // zero initialized. 35909efe848SGuillaume Chatelet 36009efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt() = default; 36109efe848SGuillaume Chatelet 36209efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt(const BigInt &other) = default; 36309efe848SGuillaume Chatelet 36487db0c06SMichael Jones template <size_t OtherBits, bool OtherSigned, typename OtherWordType> 36509efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt( 36687db0c06SMichael Jones const BigInt<OtherBits, OtherSigned, OtherWordType> &other) { 36787db0c06SMichael Jones using BigIntOther = BigInt<OtherBits, OtherSigned, OtherWordType>; 36887db0c06SMichael Jones const bool should_sign_extend = Signed && other.is_neg(); 36987db0c06SMichael Jones 37087db0c06SMichael Jones static_assert(!(Bits == OtherBits && WORD_SIZE != BigIntOther::WORD_SIZE) && 37187db0c06SMichael Jones "This is currently untested for casting between bigints with " 37287db0c06SMichael Jones "the same bit width but different word sizes."); 37387db0c06SMichael Jones 37487db0c06SMichael Jones if constexpr (BigIntOther::WORD_SIZE < WORD_SIZE) { 37587db0c06SMichael Jones // OtherWordType is smaller 37687db0c06SMichael Jones constexpr size_t WORD_SIZE_RATIO = WORD_SIZE / BigIntOther::WORD_SIZE; 37787db0c06SMichael Jones static_assert( 37887db0c06SMichael Jones (WORD_SIZE % BigIntOther::WORD_SIZE) == 0 && 37987db0c06SMichael Jones "Word types must be multiples of each other for correct conversion."); 38087db0c06SMichael Jones if constexpr (OtherBits >= Bits) { // truncate 38187db0c06SMichael Jones // for each big word 38287db0c06SMichael Jones for (size_t i = 0; i < WORD_COUNT; ++i) { 38387db0c06SMichael Jones WordType cur_word = 0; 38487db0c06SMichael Jones // combine WORD_SIZE_RATIO small words into a big word 38587db0c06SMichael Jones for (size_t j = 0; j < WORD_SIZE_RATIO; ++j) 38687db0c06SMichael Jones cur_word |= static_cast<WordType>(other[(i * WORD_SIZE_RATIO) + j]) 38787db0c06SMichael Jones << (BigIntOther::WORD_SIZE * j); 38887db0c06SMichael Jones 38987db0c06SMichael Jones val[i] = cur_word; 39087db0c06SMichael Jones } 39187db0c06SMichael Jones } else { // zero or sign extend 39287db0c06SMichael Jones size_t i = 0; 39387db0c06SMichael Jones WordType cur_word = 0; 39487db0c06SMichael Jones // for each small word 39587db0c06SMichael Jones for (; i < BigIntOther::WORD_COUNT; ++i) { 39687db0c06SMichael Jones // combine WORD_SIZE_RATIO small words into a big word 39787db0c06SMichael Jones cur_word |= static_cast<WordType>(other[i]) 39887db0c06SMichael Jones << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO)); 39987db0c06SMichael Jones // if we've completed a big word, copy it into place and reset 40087db0c06SMichael Jones if ((i % WORD_SIZE_RATIO) == WORD_SIZE_RATIO - 1) { 40187db0c06SMichael Jones val[i / WORD_SIZE_RATIO] = cur_word; 40287db0c06SMichael Jones cur_word = 0; 40387db0c06SMichael Jones } 40487db0c06SMichael Jones } 40587db0c06SMichael Jones // Pretend there are extra words of the correct sign extension as needed 40687db0c06SMichael Jones 40787db0c06SMichael Jones const WordType extension_bits = 40887db0c06SMichael Jones should_sign_extend ? cpp::numeric_limits<WordType>::max() 40987db0c06SMichael Jones : cpp::numeric_limits<WordType>::min(); 41087db0c06SMichael Jones if ((i % WORD_SIZE_RATIO) != 0) { 41187db0c06SMichael Jones cur_word |= static_cast<WordType>(extension_bits) 41287db0c06SMichael Jones << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO)); 41387db0c06SMichael Jones } 41487db0c06SMichael Jones // Copy the last word into place. 41587db0c06SMichael Jones val[(i / WORD_SIZE_RATIO)] = cur_word; 41687db0c06SMichael Jones extend((i / WORD_SIZE_RATIO) + 1, should_sign_extend); 41787db0c06SMichael Jones } 41887db0c06SMichael Jones } else if constexpr (BigIntOther::WORD_SIZE == WORD_SIZE) { 41987db0c06SMichael Jones if constexpr (OtherBits >= Bits) { // truncate 42009efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) 42109efe848SGuillaume Chatelet val[i] = other[i]; 42209efe848SGuillaume Chatelet } else { // zero or sign extend 42309efe848SGuillaume Chatelet size_t i = 0; 42487db0c06SMichael Jones for (; i < BigIntOther::WORD_COUNT; ++i) 42509efe848SGuillaume Chatelet val[i] = other[i]; 42687db0c06SMichael Jones extend(i, should_sign_extend); 42787db0c06SMichael Jones } 42887db0c06SMichael Jones } else { 42987db0c06SMichael Jones // OtherWordType is bigger. 43087db0c06SMichael Jones constexpr size_t WORD_SIZE_RATIO = BigIntOther::WORD_SIZE / WORD_SIZE; 43187db0c06SMichael Jones static_assert( 43287db0c06SMichael Jones (BigIntOther::WORD_SIZE % WORD_SIZE) == 0 && 43387db0c06SMichael Jones "Word types must be multiples of each other for correct conversion."); 43487db0c06SMichael Jones if constexpr (OtherBits >= Bits) { // truncate 43587db0c06SMichael Jones // for each small word 43687db0c06SMichael Jones for (size_t i = 0; i < WORD_COUNT; ++i) { 43787db0c06SMichael Jones // split each big word into WORD_SIZE_RATIO small words 43887db0c06SMichael Jones val[i] = static_cast<WordType>(other[i / WORD_SIZE_RATIO] >> 43987db0c06SMichael Jones ((i % WORD_SIZE_RATIO) * WORD_SIZE)); 44087db0c06SMichael Jones } 44187db0c06SMichael Jones } else { // zero or sign extend 44287db0c06SMichael Jones size_t i = 0; 44387db0c06SMichael Jones // for each big word 44487db0c06SMichael Jones for (; i < BigIntOther::WORD_COUNT; ++i) { 44587db0c06SMichael Jones // split each big word into WORD_SIZE_RATIO small words 44687db0c06SMichael Jones for (size_t j = 0; j < WORD_SIZE_RATIO; ++j) 44787db0c06SMichael Jones val[(i * WORD_SIZE_RATIO) + j] = 44887db0c06SMichael Jones static_cast<WordType>(other[i] >> (j * WORD_SIZE)); 44987db0c06SMichael Jones } 45087db0c06SMichael Jones extend(i * WORD_SIZE_RATIO, should_sign_extend); 45187db0c06SMichael Jones } 45209efe848SGuillaume Chatelet } 45309efe848SGuillaume Chatelet } 45409efe848SGuillaume Chatelet 45509efe848SGuillaume Chatelet // Construct a BigInt from a C array. 45609efe848SGuillaume Chatelet template <size_t N> LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) { 45709efe848SGuillaume Chatelet static_assert(N == WORD_COUNT); 45809efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) 45909efe848SGuillaume Chatelet val[i] = nums[i]; 46009efe848SGuillaume Chatelet } 46109efe848SGuillaume Chatelet 46209efe848SGuillaume Chatelet LIBC_INLINE constexpr explicit BigInt( 46309efe848SGuillaume Chatelet const cpp::array<WordType, WORD_COUNT> &words) { 46409efe848SGuillaume Chatelet val = words; 46509efe848SGuillaume Chatelet } 46609efe848SGuillaume Chatelet 46709efe848SGuillaume Chatelet // Initialize the first word to |v| and the rest to 0. 4687a036664SOverMighty template <typename T, typename = cpp::enable_if_t<cpp::is_integral_v<T> && 4697a036664SOverMighty !cpp::is_same_v<T, bool>>> 47009efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt(T v) { 47109efe848SGuillaume Chatelet constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT; 472*7302c8dbSNick Desaulniers const bool is_neg = v < 0; 47309efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) { 47409efe848SGuillaume Chatelet if (v == 0) { 47509efe848SGuillaume Chatelet extend(i, is_neg); 47609efe848SGuillaume Chatelet return; 47709efe848SGuillaume Chatelet } 47809efe848SGuillaume Chatelet val[i] = static_cast<WordType>(v); 47909efe848SGuillaume Chatelet if constexpr (T_SIZE > WORD_SIZE) 48009efe848SGuillaume Chatelet v >>= WORD_SIZE; 48109efe848SGuillaume Chatelet else 48209efe848SGuillaume Chatelet v = 0; 48309efe848SGuillaume Chatelet } 48409efe848SGuillaume Chatelet } 48509efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator=(const BigInt &other) = default; 48609efe848SGuillaume Chatelet 48709efe848SGuillaume Chatelet // constants 48809efe848SGuillaume Chatelet LIBC_INLINE static constexpr BigInt zero() { return BigInt(); } 48909efe848SGuillaume Chatelet LIBC_INLINE static constexpr BigInt one() { return BigInt(1); } 49009efe848SGuillaume Chatelet LIBC_INLINE static constexpr BigInt all_ones() { return ~zero(); } 49109efe848SGuillaume Chatelet LIBC_INLINE static constexpr BigInt min() { 49209efe848SGuillaume Chatelet BigInt out; 49309efe848SGuillaume Chatelet if constexpr (SIGNED) 49409efe848SGuillaume Chatelet out.set_msb(); 49509efe848SGuillaume Chatelet return out; 49609efe848SGuillaume Chatelet } 49709efe848SGuillaume Chatelet LIBC_INLINE static constexpr BigInt max() { 49809efe848SGuillaume Chatelet BigInt out = all_ones(); 49909efe848SGuillaume Chatelet if constexpr (SIGNED) 50009efe848SGuillaume Chatelet out.clear_msb(); 50109efe848SGuillaume Chatelet return out; 50209efe848SGuillaume Chatelet } 50309efe848SGuillaume Chatelet 50409efe848SGuillaume Chatelet // TODO: Reuse the Sign type. 50509efe848SGuillaume Chatelet LIBC_INLINE constexpr bool is_neg() const { return SIGNED && get_msb(); } 50609efe848SGuillaume Chatelet 507*7302c8dbSNick Desaulniers template <size_t OtherBits, bool OtherSigned, typename OtherWordType> 508*7302c8dbSNick Desaulniers LIBC_INLINE constexpr explicit 509*7302c8dbSNick Desaulniers operator BigInt<OtherBits, OtherSigned, OtherWordType>() const { 510*7302c8dbSNick Desaulniers return BigInt<OtherBits, OtherSigned, OtherWordType>(this); 511*7302c8dbSNick Desaulniers } 512*7302c8dbSNick Desaulniers 51309efe848SGuillaume Chatelet template <typename T> LIBC_INLINE constexpr explicit operator T() const { 51409efe848SGuillaume Chatelet return to<T>(); 51509efe848SGuillaume Chatelet } 51609efe848SGuillaume Chatelet 51709efe848SGuillaume Chatelet template <typename T> 51809efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t< 51909efe848SGuillaume Chatelet cpp::is_integral_v<T> && !cpp::is_same_v<T, bool>, T> 52009efe848SGuillaume Chatelet to() const { 52109efe848SGuillaume Chatelet constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT; 52209efe848SGuillaume Chatelet T lo = static_cast<T>(val[0]); 52309efe848SGuillaume Chatelet if constexpr (T_SIZE <= WORD_SIZE) 52409efe848SGuillaume Chatelet return lo; 52509efe848SGuillaume Chatelet constexpr size_t MAX_COUNT = 52609efe848SGuillaume Chatelet T_SIZE > Bits ? WORD_COUNT : T_SIZE / WORD_SIZE; 52709efe848SGuillaume Chatelet for (size_t i = 1; i < MAX_COUNT; ++i) 5287a036664SOverMighty lo += static_cast<T>(static_cast<T>(val[i]) << (WORD_SIZE * i)); 52909efe848SGuillaume Chatelet if constexpr (Signed && (T_SIZE > Bits)) { 53009efe848SGuillaume Chatelet // Extend sign for negative numbers. 53109efe848SGuillaume Chatelet constexpr T MASK = (~T(0) << Bits); 53209efe848SGuillaume Chatelet if (is_neg()) 53309efe848SGuillaume Chatelet lo |= MASK; 53409efe848SGuillaume Chatelet } 53509efe848SGuillaume Chatelet return lo; 53609efe848SGuillaume Chatelet } 53709efe848SGuillaume Chatelet 53809efe848SGuillaume Chatelet LIBC_INLINE constexpr explicit operator bool() const { return !is_zero(); } 53909efe848SGuillaume Chatelet 54009efe848SGuillaume Chatelet LIBC_INLINE constexpr bool is_zero() const { 54109efe848SGuillaume Chatelet for (auto part : val) 54209efe848SGuillaume Chatelet if (part != 0) 54309efe848SGuillaume Chatelet return false; 54409efe848SGuillaume Chatelet return true; 54509efe848SGuillaume Chatelet } 54609efe848SGuillaume Chatelet 54709efe848SGuillaume Chatelet // Add 'rhs' to this number and store the result in this number. 54809efe848SGuillaume Chatelet // Returns the carry value produced by the addition operation. 54909efe848SGuillaume Chatelet LIBC_INLINE constexpr WordType add_overflow(const BigInt &rhs) { 55009efe848SGuillaume Chatelet return multiword::add_with_carry(val, rhs.val); 55109efe848SGuillaume Chatelet } 55209efe848SGuillaume Chatelet 55309efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator+(const BigInt &other) const { 55409efe848SGuillaume Chatelet BigInt result = *this; 55509efe848SGuillaume Chatelet result.add_overflow(other); 55609efe848SGuillaume Chatelet return result; 55709efe848SGuillaume Chatelet } 55809efe848SGuillaume Chatelet 55909efe848SGuillaume Chatelet // This will only apply when initializing a variable from constant values, so 56009efe848SGuillaume Chatelet // it will always use the constexpr version of add_with_carry. 56109efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator+(BigInt &&other) const { 56209efe848SGuillaume Chatelet // We use addition commutativity to reuse 'other' and prevent allocation. 56309efe848SGuillaume Chatelet other.add_overflow(*this); // Returned carry value is ignored. 56409efe848SGuillaume Chatelet return other; 56509efe848SGuillaume Chatelet } 56609efe848SGuillaume Chatelet 56709efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator+=(const BigInt &other) { 56809efe848SGuillaume Chatelet add_overflow(other); // Returned carry value is ignored. 56909efe848SGuillaume Chatelet return *this; 57009efe848SGuillaume Chatelet } 57109efe848SGuillaume Chatelet 57209efe848SGuillaume Chatelet // Subtract 'rhs' to this number and store the result in this number. 57309efe848SGuillaume Chatelet // Returns the carry value produced by the subtraction operation. 57409efe848SGuillaume Chatelet LIBC_INLINE constexpr WordType sub_overflow(const BigInt &rhs) { 57509efe848SGuillaume Chatelet return multiword::sub_with_borrow(val, rhs.val); 57609efe848SGuillaume Chatelet } 57709efe848SGuillaume Chatelet 57809efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator-(const BigInt &other) const { 57909efe848SGuillaume Chatelet BigInt result = *this; 58009efe848SGuillaume Chatelet result.sub_overflow(other); // Returned carry value is ignored. 58109efe848SGuillaume Chatelet return result; 58209efe848SGuillaume Chatelet } 58309efe848SGuillaume Chatelet 58409efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator-(BigInt &&other) const { 58509efe848SGuillaume Chatelet BigInt result = *this; 58609efe848SGuillaume Chatelet result.sub_overflow(other); // Returned carry value is ignored. 58709efe848SGuillaume Chatelet return result; 58809efe848SGuillaume Chatelet } 58909efe848SGuillaume Chatelet 59009efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator-=(const BigInt &other) { 59109efe848SGuillaume Chatelet // TODO(lntue): Set overflow flag / errno when carry is true. 59209efe848SGuillaume Chatelet sub_overflow(other); // Returned carry value is ignored. 59309efe848SGuillaume Chatelet return *this; 59409efe848SGuillaume Chatelet } 59509efe848SGuillaume Chatelet 59609efe848SGuillaume Chatelet // Multiply this number with x and store the result in this number. 59709efe848SGuillaume Chatelet LIBC_INLINE constexpr WordType mul(WordType x) { 59809efe848SGuillaume Chatelet return multiword::scalar_multiply_with_carry(val, x); 59909efe848SGuillaume Chatelet } 60009efe848SGuillaume Chatelet 60109efe848SGuillaume Chatelet // Return the full product. 60209efe848SGuillaume Chatelet template <size_t OtherBits> 60309efe848SGuillaume Chatelet LIBC_INLINE constexpr auto 60409efe848SGuillaume Chatelet ful_mul(const BigInt<OtherBits, Signed, WordType> &other) const { 60509efe848SGuillaume Chatelet BigInt<Bits + OtherBits, Signed, WordType> result; 60609efe848SGuillaume Chatelet multiword::multiply_with_carry(result.val, val, other.val); 60709efe848SGuillaume Chatelet return result; 60809efe848SGuillaume Chatelet } 60909efe848SGuillaume Chatelet 61009efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator*(const BigInt &other) const { 61109efe848SGuillaume Chatelet // Perform full mul and truncate. 61209efe848SGuillaume Chatelet return BigInt(ful_mul(other)); 61309efe848SGuillaume Chatelet } 61409efe848SGuillaume Chatelet 61509efe848SGuillaume Chatelet // Fast hi part of the full product. The normal product `operator*` returns 61609efe848SGuillaume Chatelet // `Bits` least significant bits of the full product, while this function will 61709efe848SGuillaume Chatelet // approximate `Bits` most significant bits of the full product with errors 61809efe848SGuillaume Chatelet // bounded by: 61909efe848SGuillaume Chatelet // 0 <= (a.full_mul(b) >> Bits) - a.quick_mul_hi(b)) <= WORD_COUNT - 1. 62009efe848SGuillaume Chatelet // 62109efe848SGuillaume Chatelet // An example usage of this is to quickly (but less accurately) compute the 62209efe848SGuillaume Chatelet // product of (normalized) mantissas of floating point numbers: 62309efe848SGuillaume Chatelet // (mant_1, mant_2) -> quick_mul_hi -> normalize leading bit 62409efe848SGuillaume Chatelet // is much more efficient than: 62509efe848SGuillaume Chatelet // (mant_1, mant_2) -> ful_mul -> normalize leading bit 62609efe848SGuillaume Chatelet // -> convert back to same Bits width by shifting/rounding, 62709efe848SGuillaume Chatelet // especially for higher precisions. 62809efe848SGuillaume Chatelet // 62909efe848SGuillaume Chatelet // Performance summary: 63009efe848SGuillaume Chatelet // Number of 64-bit x 64-bit -> 128-bit multiplications performed. 63109efe848SGuillaume Chatelet // Bits WORD_COUNT ful_mul quick_mul_hi Error bound 63209efe848SGuillaume Chatelet // 128 2 4 3 1 63309efe848SGuillaume Chatelet // 196 3 9 6 2 63409efe848SGuillaume Chatelet // 256 4 16 10 3 63509efe848SGuillaume Chatelet // 512 8 64 36 7 63609efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const { 63709efe848SGuillaume Chatelet BigInt result; 63809efe848SGuillaume Chatelet multiword::quick_mul_hi(result.val, val, other.val); 63909efe848SGuillaume Chatelet return result; 64009efe848SGuillaume Chatelet } 64109efe848SGuillaume Chatelet 64209efe848SGuillaume Chatelet // BigInt(x).pow_n(n) computes x ^ n. 64309efe848SGuillaume Chatelet // Note 0 ^ 0 == 1. 64409efe848SGuillaume Chatelet LIBC_INLINE constexpr void pow_n(uint64_t power) { 64509efe848SGuillaume Chatelet static_assert(!Signed); 64609efe848SGuillaume Chatelet BigInt result = one(); 64709efe848SGuillaume Chatelet BigInt cur_power = *this; 64809efe848SGuillaume Chatelet while (power > 0) { 64909efe848SGuillaume Chatelet if ((power % 2) > 0) 65009efe848SGuillaume Chatelet result *= cur_power; 65109efe848SGuillaume Chatelet power >>= 1; 65209efe848SGuillaume Chatelet cur_power *= cur_power; 65309efe848SGuillaume Chatelet } 65409efe848SGuillaume Chatelet *this = result; 65509efe848SGuillaume Chatelet } 65609efe848SGuillaume Chatelet 65709efe848SGuillaume Chatelet // Performs inplace signed / unsigned division. Returns remainder if not 65809efe848SGuillaume Chatelet // dividing by zero. 65909efe848SGuillaume Chatelet // For signed numbers it behaves like C++ signed integer division. 66009efe848SGuillaume Chatelet // That is by truncating the fractionnal part 66109efe848SGuillaume Chatelet // https://stackoverflow.com/a/3602857 66209efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::optional<BigInt> div(const BigInt ÷r) { 66309efe848SGuillaume Chatelet if (LIBC_UNLIKELY(divider.is_zero())) 66409efe848SGuillaume Chatelet return cpp::nullopt; 66509efe848SGuillaume Chatelet if (LIBC_UNLIKELY(divider == BigInt::one())) 66609efe848SGuillaume Chatelet return BigInt::zero(); 66709efe848SGuillaume Chatelet Division result; 66809efe848SGuillaume Chatelet if constexpr (SIGNED) 66909efe848SGuillaume Chatelet result = divide_signed(*this, divider); 67009efe848SGuillaume Chatelet else 67109efe848SGuillaume Chatelet result = divide_unsigned(*this, divider); 67209efe848SGuillaume Chatelet *this = result.quotient; 67309efe848SGuillaume Chatelet return result.remainder; 67409efe848SGuillaume Chatelet } 67509efe848SGuillaume Chatelet 67609efe848SGuillaume Chatelet // Efficiently perform BigInt / (x * 2^e), where x is a half-word-size 67709efe848SGuillaume Chatelet // unsigned integer, and return the remainder. The main idea is as follow: 67809efe848SGuillaume Chatelet // Let q = y / (x * 2^e) be the quotient, and 67909efe848SGuillaume Chatelet // r = y % (x * 2^e) be the remainder. 68009efe848SGuillaume Chatelet // First, notice that: 68109efe848SGuillaume Chatelet // r % (2^e) = y % (2^e), 68209efe848SGuillaume Chatelet // so we just need to focus on all the bits of y that is >= 2^e. 68309efe848SGuillaume Chatelet // To speed up the shift-and-add steps, we only use x as the divisor, and 68409efe848SGuillaume Chatelet // performing 32-bit shiftings instead of bit-by-bit shiftings. 68509efe848SGuillaume Chatelet // Since the remainder of each division step < x < 2^(WORD_SIZE / 2), the 68609efe848SGuillaume Chatelet // computation of each step is now properly contained within WordType. 68709efe848SGuillaume Chatelet // And finally we perform some extra alignment steps for the remaining bits. 68809efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::optional<BigInt> 68909efe848SGuillaume Chatelet div_uint_half_times_pow_2(multiword::half_width_t<WordType> x, size_t e) { 69009efe848SGuillaume Chatelet BigInt remainder; 69109efe848SGuillaume Chatelet if (x == 0) 69209efe848SGuillaume Chatelet return cpp::nullopt; 69309efe848SGuillaume Chatelet if (e >= Bits) { 69409efe848SGuillaume Chatelet remainder = *this; 69509efe848SGuillaume Chatelet *this = BigInt<Bits, false, WordType>(); 69609efe848SGuillaume Chatelet return remainder; 69709efe848SGuillaume Chatelet } 69809efe848SGuillaume Chatelet BigInt quotient; 69909efe848SGuillaume Chatelet WordType x_word = static_cast<WordType>(x); 70009efe848SGuillaume Chatelet constexpr size_t LOG2_WORD_SIZE = cpp::bit_width(WORD_SIZE) - 1; 70109efe848SGuillaume Chatelet constexpr size_t HALF_WORD_SIZE = WORD_SIZE >> 1; 70209efe848SGuillaume Chatelet constexpr WordType HALF_MASK = ((WordType(1) << HALF_WORD_SIZE) - 1); 70309efe848SGuillaume Chatelet // lower = smallest multiple of WORD_SIZE that is >= e. 70409efe848SGuillaume Chatelet size_t lower = ((e >> LOG2_WORD_SIZE) + ((e & (WORD_SIZE - 1)) != 0)) 70509efe848SGuillaume Chatelet << LOG2_WORD_SIZE; 70609efe848SGuillaume Chatelet // lower_pos is the index of the closest WORD_SIZE-bit chunk >= 2^e. 70709efe848SGuillaume Chatelet size_t lower_pos = lower / WORD_SIZE; 70809efe848SGuillaume Chatelet // Keep track of current remainder mod x * 2^(32*i) 70909efe848SGuillaume Chatelet WordType rem = 0; 71009efe848SGuillaume Chatelet // pos is the index of the current 64-bit chunk that we are processing. 71109efe848SGuillaume Chatelet size_t pos = WORD_COUNT; 71209efe848SGuillaume Chatelet 71309efe848SGuillaume Chatelet // TODO: look into if constexpr(Bits > 256) skip leading zeroes. 71409efe848SGuillaume Chatelet 71509efe848SGuillaume Chatelet for (size_t q_pos = WORD_COUNT - lower_pos; q_pos > 0; --q_pos) { 71609efe848SGuillaume Chatelet // q_pos is 1 + the index of the current WORD_SIZE-bit chunk of the 71709efe848SGuillaume Chatelet // quotient being processed. Performing the division / modulus with 71809efe848SGuillaume Chatelet // divisor: 71909efe848SGuillaume Chatelet // x * 2^(WORD_SIZE*q_pos - WORD_SIZE/2), 72009efe848SGuillaume Chatelet // i.e. using the upper (WORD_SIZE/2)-bit of the current WORD_SIZE-bit 72109efe848SGuillaume Chatelet // chunk. 72209efe848SGuillaume Chatelet rem <<= HALF_WORD_SIZE; 72309efe848SGuillaume Chatelet rem += val[--pos] >> HALF_WORD_SIZE; 72409efe848SGuillaume Chatelet WordType q_tmp = rem / x_word; 72509efe848SGuillaume Chatelet rem %= x_word; 72609efe848SGuillaume Chatelet 72709efe848SGuillaume Chatelet // Performing the division / modulus with divisor: 72809efe848SGuillaume Chatelet // x * 2^(WORD_SIZE*(q_pos - 1)), 72909efe848SGuillaume Chatelet // i.e. using the lower (WORD_SIZE/2)-bit of the current WORD_SIZE-bit 73009efe848SGuillaume Chatelet // chunk. 73109efe848SGuillaume Chatelet rem <<= HALF_WORD_SIZE; 73209efe848SGuillaume Chatelet rem += val[pos] & HALF_MASK; 73309efe848SGuillaume Chatelet quotient.val[q_pos - 1] = (q_tmp << HALF_WORD_SIZE) + rem / x_word; 73409efe848SGuillaume Chatelet rem %= x_word; 73509efe848SGuillaume Chatelet } 73609efe848SGuillaume Chatelet 73709efe848SGuillaume Chatelet // So far, what we have is: 73809efe848SGuillaume Chatelet // quotient = y / (x * 2^lower), and 73909efe848SGuillaume Chatelet // rem = (y % (x * 2^lower)) / 2^lower. 74009efe848SGuillaume Chatelet // If (lower > e), we will need to perform an extra adjustment of the 74109efe848SGuillaume Chatelet // quotient and remainder, namely: 74209efe848SGuillaume Chatelet // y / (x * 2^e) = [ y / (x * 2^lower) ] * 2^(lower - e) + 74309efe848SGuillaume Chatelet // + (rem * 2^(lower - e)) / x 74409efe848SGuillaume Chatelet // (y % (x * 2^e)) / 2^e = (rem * 2^(lower - e)) % x 74509efe848SGuillaume Chatelet size_t last_shift = lower - e; 74609efe848SGuillaume Chatelet 74709efe848SGuillaume Chatelet if (last_shift > 0) { 74809efe848SGuillaume Chatelet // quotient * 2^(lower - e) 74909efe848SGuillaume Chatelet quotient <<= last_shift; 75009efe848SGuillaume Chatelet WordType q_tmp = 0; 75109efe848SGuillaume Chatelet WordType d = val[--pos]; 75209efe848SGuillaume Chatelet if (last_shift >= HALF_WORD_SIZE) { 75309efe848SGuillaume Chatelet // The shifting (rem * 2^(lower - e)) might overflow WordTyoe, so we 75409efe848SGuillaume Chatelet // perform a HALF_WORD_SIZE-bit shift first. 75509efe848SGuillaume Chatelet rem <<= HALF_WORD_SIZE; 75609efe848SGuillaume Chatelet rem += d >> HALF_WORD_SIZE; 75709efe848SGuillaume Chatelet d &= HALF_MASK; 75809efe848SGuillaume Chatelet q_tmp = rem / x_word; 75909efe848SGuillaume Chatelet rem %= x_word; 76009efe848SGuillaume Chatelet last_shift -= HALF_WORD_SIZE; 76109efe848SGuillaume Chatelet } else { 76209efe848SGuillaume Chatelet // Only use the upper HALF_WORD_SIZE-bit of the current WORD_SIZE-bit 76309efe848SGuillaume Chatelet // chunk. 76409efe848SGuillaume Chatelet d >>= HALF_WORD_SIZE; 76509efe848SGuillaume Chatelet } 76609efe848SGuillaume Chatelet 76709efe848SGuillaume Chatelet if (last_shift > 0) { 76809efe848SGuillaume Chatelet rem <<= HALF_WORD_SIZE; 76909efe848SGuillaume Chatelet rem += d; 77009efe848SGuillaume Chatelet q_tmp <<= last_shift; 77109efe848SGuillaume Chatelet x_word <<= HALF_WORD_SIZE - last_shift; 77209efe848SGuillaume Chatelet q_tmp += rem / x_word; 77309efe848SGuillaume Chatelet rem %= x_word; 77409efe848SGuillaume Chatelet } 77509efe848SGuillaume Chatelet 77609efe848SGuillaume Chatelet quotient.val[0] += q_tmp; 77709efe848SGuillaume Chatelet 77809efe848SGuillaume Chatelet if (lower - e <= HALF_WORD_SIZE) { 77909efe848SGuillaume Chatelet // The remainder rem * 2^(lower - e) might overflow to the higher 78009efe848SGuillaume Chatelet // WORD_SIZE-bit chunk. 78109efe848SGuillaume Chatelet if (pos < WORD_COUNT - 1) { 78209efe848SGuillaume Chatelet remainder[pos + 1] = rem >> HALF_WORD_SIZE; 78309efe848SGuillaume Chatelet } 78409efe848SGuillaume Chatelet remainder[pos] = (rem << HALF_WORD_SIZE) + (val[pos] & HALF_MASK); 78509efe848SGuillaume Chatelet } else { 78609efe848SGuillaume Chatelet remainder[pos] = rem; 78709efe848SGuillaume Chatelet } 78809efe848SGuillaume Chatelet 78909efe848SGuillaume Chatelet } else { 79009efe848SGuillaume Chatelet remainder[pos] = rem; 79109efe848SGuillaume Chatelet } 79209efe848SGuillaume Chatelet 79309efe848SGuillaume Chatelet // Set the remaining lower bits of the remainder. 79409efe848SGuillaume Chatelet for (; pos > 0; --pos) { 79509efe848SGuillaume Chatelet remainder[pos - 1] = val[pos - 1]; 79609efe848SGuillaume Chatelet } 79709efe848SGuillaume Chatelet 79809efe848SGuillaume Chatelet *this = quotient; 79909efe848SGuillaume Chatelet return remainder; 80009efe848SGuillaume Chatelet } 80109efe848SGuillaume Chatelet 80209efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator/(const BigInt &other) const { 80309efe848SGuillaume Chatelet BigInt result(*this); 80409efe848SGuillaume Chatelet result.div(other); 80509efe848SGuillaume Chatelet return result; 80609efe848SGuillaume Chatelet } 80709efe848SGuillaume Chatelet 80809efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator/=(const BigInt &other) { 80909efe848SGuillaume Chatelet div(other); 81009efe848SGuillaume Chatelet return *this; 81109efe848SGuillaume Chatelet } 81209efe848SGuillaume Chatelet 81309efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator%(const BigInt &other) const { 81409efe848SGuillaume Chatelet BigInt result(*this); 81509efe848SGuillaume Chatelet return *result.div(other); 81609efe848SGuillaume Chatelet } 81709efe848SGuillaume Chatelet 8180ccec541SMikhail R. Gadelha LIBC_INLINE constexpr BigInt operator%=(const BigInt &other) { 819dffa28faSMikhail R. Gadelha *this = *this % other; 820dffa28faSMikhail R. Gadelha return *this; 8210ccec541SMikhail R. Gadelha } 8220ccec541SMikhail R. Gadelha 82309efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator*=(const BigInt &other) { 82409efe848SGuillaume Chatelet *this = *this * other; 82509efe848SGuillaume Chatelet return *this; 82609efe848SGuillaume Chatelet } 82709efe848SGuillaume Chatelet 82809efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator<<=(size_t s) { 82909efe848SGuillaume Chatelet val = multiword::shift<multiword::LEFT, SIGNED>(val, s); 83009efe848SGuillaume Chatelet return *this; 83109efe848SGuillaume Chatelet } 83209efe848SGuillaume Chatelet 83309efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator<<(size_t s) const { 83409efe848SGuillaume Chatelet return BigInt(multiword::shift<multiword::LEFT, SIGNED>(val, s)); 83509efe848SGuillaume Chatelet } 83609efe848SGuillaume Chatelet 83709efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator>>=(size_t s) { 83809efe848SGuillaume Chatelet val = multiword::shift<multiword::RIGHT, SIGNED>(val, s); 83909efe848SGuillaume Chatelet return *this; 84009efe848SGuillaume Chatelet } 84109efe848SGuillaume Chatelet 84209efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator>>(size_t s) const { 84309efe848SGuillaume Chatelet return BigInt(multiword::shift<multiword::RIGHT, SIGNED>(val, s)); 84409efe848SGuillaume Chatelet } 84509efe848SGuillaume Chatelet 84609efe848SGuillaume Chatelet #define DEFINE_BINOP(OP) \ 84709efe848SGuillaume Chatelet LIBC_INLINE friend constexpr BigInt operator OP(const BigInt &lhs, \ 84809efe848SGuillaume Chatelet const BigInt &rhs) { \ 84909efe848SGuillaume Chatelet BigInt result; \ 85009efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) \ 85109efe848SGuillaume Chatelet result[i] = lhs[i] OP rhs[i]; \ 85209efe848SGuillaume Chatelet return result; \ 85309efe848SGuillaume Chatelet } \ 85409efe848SGuillaume Chatelet LIBC_INLINE friend constexpr BigInt operator OP##=(BigInt &lhs, \ 85509efe848SGuillaume Chatelet const BigInt &rhs) { \ 85609efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) \ 85709efe848SGuillaume Chatelet lhs[i] OP## = rhs[i]; \ 85809efe848SGuillaume Chatelet return lhs; \ 85909efe848SGuillaume Chatelet } 86009efe848SGuillaume Chatelet 86109efe848SGuillaume Chatelet DEFINE_BINOP(&) // & and &= 86209efe848SGuillaume Chatelet DEFINE_BINOP(|) // | and |= 86309efe848SGuillaume Chatelet DEFINE_BINOP(^) // ^ and ^= 86409efe848SGuillaume Chatelet #undef DEFINE_BINOP 86509efe848SGuillaume Chatelet 86609efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator~() const { 86709efe848SGuillaume Chatelet BigInt result; 86809efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) 86909efe848SGuillaume Chatelet result[i] = ~val[i]; 87009efe848SGuillaume Chatelet return result; 87109efe848SGuillaume Chatelet } 87209efe848SGuillaume Chatelet 87309efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator-() const { 87409efe848SGuillaume Chatelet BigInt result(*this); 87509efe848SGuillaume Chatelet result.negate(); 87609efe848SGuillaume Chatelet return result; 87709efe848SGuillaume Chatelet } 87809efe848SGuillaume Chatelet 87909efe848SGuillaume Chatelet LIBC_INLINE friend constexpr bool operator==(const BigInt &lhs, 88009efe848SGuillaume Chatelet const BigInt &rhs) { 88109efe848SGuillaume Chatelet for (size_t i = 0; i < WORD_COUNT; ++i) 88209efe848SGuillaume Chatelet if (lhs.val[i] != rhs.val[i]) 88309efe848SGuillaume Chatelet return false; 88409efe848SGuillaume Chatelet return true; 88509efe848SGuillaume Chatelet } 88609efe848SGuillaume Chatelet 88709efe848SGuillaume Chatelet LIBC_INLINE friend constexpr bool operator!=(const BigInt &lhs, 88809efe848SGuillaume Chatelet const BigInt &rhs) { 88909efe848SGuillaume Chatelet return !(lhs == rhs); 89009efe848SGuillaume Chatelet } 89109efe848SGuillaume Chatelet 89209efe848SGuillaume Chatelet LIBC_INLINE friend constexpr bool operator>(const BigInt &lhs, 89309efe848SGuillaume Chatelet const BigInt &rhs) { 89409efe848SGuillaume Chatelet return cmp(lhs, rhs) > 0; 89509efe848SGuillaume Chatelet } 89609efe848SGuillaume Chatelet LIBC_INLINE friend constexpr bool operator>=(const BigInt &lhs, 89709efe848SGuillaume Chatelet const BigInt &rhs) { 89809efe848SGuillaume Chatelet return cmp(lhs, rhs) >= 0; 89909efe848SGuillaume Chatelet } 90009efe848SGuillaume Chatelet LIBC_INLINE friend constexpr bool operator<(const BigInt &lhs, 90109efe848SGuillaume Chatelet const BigInt &rhs) { 90209efe848SGuillaume Chatelet return cmp(lhs, rhs) < 0; 90309efe848SGuillaume Chatelet } 90409efe848SGuillaume Chatelet LIBC_INLINE friend constexpr bool operator<=(const BigInt &lhs, 90509efe848SGuillaume Chatelet const BigInt &rhs) { 90609efe848SGuillaume Chatelet return cmp(lhs, rhs) <= 0; 90709efe848SGuillaume Chatelet } 90809efe848SGuillaume Chatelet 90909efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator++() { 91009efe848SGuillaume Chatelet increment(); 91109efe848SGuillaume Chatelet return *this; 91209efe848SGuillaume Chatelet } 91309efe848SGuillaume Chatelet 91409efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator++(int) { 91509efe848SGuillaume Chatelet BigInt oldval(*this); 91609efe848SGuillaume Chatelet increment(); 91709efe848SGuillaume Chatelet return oldval; 91809efe848SGuillaume Chatelet } 91909efe848SGuillaume Chatelet 92009efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt &operator--() { 92109efe848SGuillaume Chatelet decrement(); 92209efe848SGuillaume Chatelet return *this; 92309efe848SGuillaume Chatelet } 92409efe848SGuillaume Chatelet 92509efe848SGuillaume Chatelet LIBC_INLINE constexpr BigInt operator--(int) { 92609efe848SGuillaume Chatelet BigInt oldval(*this); 92709efe848SGuillaume Chatelet decrement(); 92809efe848SGuillaume Chatelet return oldval; 92909efe848SGuillaume Chatelet } 93009efe848SGuillaume Chatelet 93109efe848SGuillaume Chatelet // Return the i-th word of the number. 93209efe848SGuillaume Chatelet LIBC_INLINE constexpr const WordType &operator[](size_t i) const { 93309efe848SGuillaume Chatelet return val[i]; 93409efe848SGuillaume Chatelet } 93509efe848SGuillaume Chatelet 93609efe848SGuillaume Chatelet // Return the i-th word of the number. 93709efe848SGuillaume Chatelet LIBC_INLINE constexpr WordType &operator[](size_t i) { return val[i]; } 93809efe848SGuillaume Chatelet 93909efe848SGuillaume Chatelet private: 94009efe848SGuillaume Chatelet LIBC_INLINE friend constexpr int cmp(const BigInt &lhs, const BigInt &rhs) { 94109efe848SGuillaume Chatelet constexpr auto compare = [](WordType a, WordType b) { 94209efe848SGuillaume Chatelet return a == b ? 0 : a > b ? 1 : -1; 94309efe848SGuillaume Chatelet }; 94409efe848SGuillaume Chatelet if constexpr (Signed) { 94509efe848SGuillaume Chatelet const bool lhs_is_neg = lhs.is_neg(); 94609efe848SGuillaume Chatelet const bool rhs_is_neg = rhs.is_neg(); 94709efe848SGuillaume Chatelet if (lhs_is_neg != rhs_is_neg) 94809efe848SGuillaume Chatelet return rhs_is_neg ? 1 : -1; 94909efe848SGuillaume Chatelet } 95009efe848SGuillaume Chatelet for (size_t i = WORD_COUNT; i-- > 0;) 95109efe848SGuillaume Chatelet if (auto cmp = compare(lhs[i], rhs[i]); cmp != 0) 95209efe848SGuillaume Chatelet return cmp; 95309efe848SGuillaume Chatelet return 0; 95409efe848SGuillaume Chatelet } 95509efe848SGuillaume Chatelet 95609efe848SGuillaume Chatelet LIBC_INLINE constexpr void bitwise_not() { 95709efe848SGuillaume Chatelet for (auto &part : val) 95809efe848SGuillaume Chatelet part = ~part; 95909efe848SGuillaume Chatelet } 96009efe848SGuillaume Chatelet 96109efe848SGuillaume Chatelet LIBC_INLINE constexpr void negate() { 96209efe848SGuillaume Chatelet bitwise_not(); 96309efe848SGuillaume Chatelet increment(); 96409efe848SGuillaume Chatelet } 96509efe848SGuillaume Chatelet 96609efe848SGuillaume Chatelet LIBC_INLINE constexpr void increment() { 96709efe848SGuillaume Chatelet multiword::add_with_carry(val, cpp::array<WordType, 1>{1}); 96809efe848SGuillaume Chatelet } 96909efe848SGuillaume Chatelet 97009efe848SGuillaume Chatelet LIBC_INLINE constexpr void decrement() { 97109efe848SGuillaume Chatelet multiword::add_with_carry(val, cpp::array<WordType, 1>{1}); 97209efe848SGuillaume Chatelet } 97309efe848SGuillaume Chatelet 97409efe848SGuillaume Chatelet LIBC_INLINE constexpr void extend(size_t index, bool is_neg) { 97509efe848SGuillaume Chatelet const WordType value = is_neg ? cpp::numeric_limits<WordType>::max() 97609efe848SGuillaume Chatelet : cpp::numeric_limits<WordType>::min(); 97709efe848SGuillaume Chatelet for (size_t i = index; i < WORD_COUNT; ++i) 97809efe848SGuillaume Chatelet val[i] = value; 97909efe848SGuillaume Chatelet } 98009efe848SGuillaume Chatelet 98109efe848SGuillaume Chatelet LIBC_INLINE constexpr bool get_msb() const { 98209efe848SGuillaume Chatelet return val.back() >> (WORD_SIZE - 1); 98309efe848SGuillaume Chatelet } 98409efe848SGuillaume Chatelet 98509efe848SGuillaume Chatelet LIBC_INLINE constexpr void set_msb() { 98609efe848SGuillaume Chatelet val.back() |= mask_leading_ones<WordType, 1>(); 98709efe848SGuillaume Chatelet } 98809efe848SGuillaume Chatelet 98909efe848SGuillaume Chatelet LIBC_INLINE constexpr void clear_msb() { 99009efe848SGuillaume Chatelet val.back() &= mask_trailing_ones<WordType, WORD_SIZE - 1>(); 99109efe848SGuillaume Chatelet } 99209efe848SGuillaume Chatelet 99309efe848SGuillaume Chatelet LIBC_INLINE constexpr void set_bit(size_t i) { 99409efe848SGuillaume Chatelet const size_t word_index = i / WORD_SIZE; 99509efe848SGuillaume Chatelet val[word_index] |= WordType(1) << (i % WORD_SIZE); 99609efe848SGuillaume Chatelet } 99709efe848SGuillaume Chatelet 99809efe848SGuillaume Chatelet LIBC_INLINE constexpr static Division divide_unsigned(const BigInt ÷nd, 99909efe848SGuillaume Chatelet const BigInt ÷r) { 100009efe848SGuillaume Chatelet BigInt remainder = dividend; 100109efe848SGuillaume Chatelet BigInt quotient; 100209efe848SGuillaume Chatelet if (remainder >= divider) { 100309efe848SGuillaume Chatelet BigInt subtractor = divider; 100409efe848SGuillaume Chatelet int cur_bit = multiword::countl_zero(subtractor.val) - 100509efe848SGuillaume Chatelet multiword::countl_zero(remainder.val); 100609efe848SGuillaume Chatelet subtractor <<= cur_bit; 100709efe848SGuillaume Chatelet for (; cur_bit >= 0 && remainder > 0; --cur_bit, subtractor >>= 1) { 100809efe848SGuillaume Chatelet if (remainder < subtractor) 100909efe848SGuillaume Chatelet continue; 101009efe848SGuillaume Chatelet remainder -= subtractor; 101109efe848SGuillaume Chatelet quotient.set_bit(cur_bit); 101209efe848SGuillaume Chatelet } 101309efe848SGuillaume Chatelet } 101409efe848SGuillaume Chatelet return Division{quotient, remainder}; 101509efe848SGuillaume Chatelet } 101609efe848SGuillaume Chatelet 101709efe848SGuillaume Chatelet LIBC_INLINE constexpr static Division divide_signed(const BigInt ÷nd, 101809efe848SGuillaume Chatelet const BigInt ÷r) { 101909efe848SGuillaume Chatelet // Special case because it is not possible to negate the min value of a 102009efe848SGuillaume Chatelet // signed integer. 102109efe848SGuillaume Chatelet if (dividend == min() && divider == min()) 102209efe848SGuillaume Chatelet return Division{one(), zero()}; 102309efe848SGuillaume Chatelet // 1. Convert the dividend and divisor to unsigned representation. 102409efe848SGuillaume Chatelet unsigned_type udividend(dividend); 102509efe848SGuillaume Chatelet unsigned_type udivider(divider); 102609efe848SGuillaume Chatelet // 2. Negate the dividend if it's negative, and similarly for the divisor. 102709efe848SGuillaume Chatelet const bool dividend_is_neg = dividend.is_neg(); 102809efe848SGuillaume Chatelet const bool divider_is_neg = divider.is_neg(); 102909efe848SGuillaume Chatelet if (dividend_is_neg) 103009efe848SGuillaume Chatelet udividend.negate(); 103109efe848SGuillaume Chatelet if (divider_is_neg) 103209efe848SGuillaume Chatelet udivider.negate(); 103309efe848SGuillaume Chatelet // 3. Use unsigned multiword division algorithm. 103409efe848SGuillaume Chatelet const auto unsigned_result = divide_unsigned(udividend, udivider); 103509efe848SGuillaume Chatelet // 4. Convert the quotient and remainder to signed representation. 103609efe848SGuillaume Chatelet Division result; 103709efe848SGuillaume Chatelet result.quotient = signed_type(unsigned_result.quotient); 103809efe848SGuillaume Chatelet result.remainder = signed_type(unsigned_result.remainder); 103909efe848SGuillaume Chatelet // 5. Negate the quotient if the dividend and divisor had opposite signs. 104009efe848SGuillaume Chatelet if (dividend_is_neg != divider_is_neg) 104109efe848SGuillaume Chatelet result.quotient.negate(); 104209efe848SGuillaume Chatelet // 6. Negate the remainder if the dividend was negative. 104309efe848SGuillaume Chatelet if (dividend_is_neg) 104409efe848SGuillaume Chatelet result.remainder.negate(); 104509efe848SGuillaume Chatelet return result; 104609efe848SGuillaume Chatelet } 104709efe848SGuillaume Chatelet 104809efe848SGuillaume Chatelet friend signed_type; 104909efe848SGuillaume Chatelet friend unsigned_type; 105009efe848SGuillaume Chatelet }; 105109efe848SGuillaume Chatelet 105209efe848SGuillaume Chatelet namespace internal { 105309efe848SGuillaume Chatelet // We default BigInt's WordType to 'uint64_t' or 'uint32_t' depending on type 105409efe848SGuillaume Chatelet // availability. 105509efe848SGuillaume Chatelet template <size_t Bits> 105609efe848SGuillaume Chatelet struct WordTypeSelector : cpp::type_identity< 105709efe848SGuillaume Chatelet #ifdef LIBC_TYPES_HAS_INT64 105809efe848SGuillaume Chatelet uint64_t 105909efe848SGuillaume Chatelet #else 106009efe848SGuillaume Chatelet uint32_t 106109efe848SGuillaume Chatelet #endif // LIBC_TYPES_HAS_INT64 106209efe848SGuillaume Chatelet > { 106309efe848SGuillaume Chatelet }; 10646b21e170SOverMighty // Except if we request 16 or 32 bits explicitly. 10656b21e170SOverMighty template <> struct WordTypeSelector<16> : cpp::type_identity<uint16_t> {}; 106609efe848SGuillaume Chatelet template <> struct WordTypeSelector<32> : cpp::type_identity<uint32_t> {}; 1067*7302c8dbSNick Desaulniers template <> struct WordTypeSelector<96> : cpp::type_identity<uint32_t> {}; 1068*7302c8dbSNick Desaulniers 106909efe848SGuillaume Chatelet template <size_t Bits> 107009efe848SGuillaume Chatelet using WordTypeSelectorT = typename WordTypeSelector<Bits>::type; 107109efe848SGuillaume Chatelet } // namespace internal 107209efe848SGuillaume Chatelet 107309efe848SGuillaume Chatelet template <size_t Bits> 107409efe848SGuillaume Chatelet using UInt = BigInt<Bits, false, internal::WordTypeSelectorT<Bits>>; 107509efe848SGuillaume Chatelet 107609efe848SGuillaume Chatelet template <size_t Bits> 107709efe848SGuillaume Chatelet using Int = BigInt<Bits, true, internal::WordTypeSelectorT<Bits>>; 107809efe848SGuillaume Chatelet 1079f3aceeeeSOverMighty // Provides limits of BigInt. 1080f3aceeeeSOverMighty template <size_t Bits, bool Signed, typename T> 1081f3aceeeeSOverMighty struct cpp::numeric_limits<BigInt<Bits, Signed, T>> { 1082f3aceeeeSOverMighty LIBC_INLINE static constexpr BigInt<Bits, Signed, T> max() { 1083f3aceeeeSOverMighty return BigInt<Bits, Signed, T>::max(); 1084f3aceeeeSOverMighty } 1085f3aceeeeSOverMighty LIBC_INLINE static constexpr BigInt<Bits, Signed, T> min() { 1086f3aceeeeSOverMighty return BigInt<Bits, Signed, T>::min(); 1087f3aceeeeSOverMighty } 108809efe848SGuillaume Chatelet // Meant to match std::numeric_limits interface. 108909efe848SGuillaume Chatelet // NOLINTNEXTLINE(readability-identifier-naming) 1090f3aceeeeSOverMighty LIBC_INLINE_VAR static constexpr int digits = Bits - Signed; 109109efe848SGuillaume Chatelet }; 109209efe848SGuillaume Chatelet 109309efe848SGuillaume Chatelet // type traits to determine whether a T is a BigInt. 109409efe848SGuillaume Chatelet template <typename T> struct is_big_int : cpp::false_type {}; 109509efe848SGuillaume Chatelet 109609efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename T> 109709efe848SGuillaume Chatelet struct is_big_int<BigInt<Bits, Signed, T>> : cpp::true_type {}; 109809efe848SGuillaume Chatelet 109909efe848SGuillaume Chatelet template <class T> 110009efe848SGuillaume Chatelet LIBC_INLINE_VAR constexpr bool is_big_int_v = is_big_int<T>::value; 110109efe848SGuillaume Chatelet 110209efe848SGuillaume Chatelet // extensions of type traits to include BigInt 110309efe848SGuillaume Chatelet 110409efe848SGuillaume Chatelet // is_integral_or_big_int 110509efe848SGuillaume Chatelet template <typename T> 110609efe848SGuillaume Chatelet struct is_integral_or_big_int 110709efe848SGuillaume Chatelet : cpp::bool_constant<(cpp::is_integral_v<T> || is_big_int_v<T>)> {}; 110809efe848SGuillaume Chatelet 110909efe848SGuillaume Chatelet template <typename T> 111009efe848SGuillaume Chatelet LIBC_INLINE_VAR constexpr bool is_integral_or_big_int_v = 111109efe848SGuillaume Chatelet is_integral_or_big_int<T>::value; 111209efe848SGuillaume Chatelet 111309efe848SGuillaume Chatelet // make_big_int_unsigned 111409efe848SGuillaume Chatelet template <typename T> struct make_big_int_unsigned; 111509efe848SGuillaume Chatelet 111609efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename T> 111709efe848SGuillaume Chatelet struct make_big_int_unsigned<BigInt<Bits, Signed, T>> 111809efe848SGuillaume Chatelet : cpp::type_identity<BigInt<Bits, false, T>> {}; 111909efe848SGuillaume Chatelet 112009efe848SGuillaume Chatelet template <typename T> 112109efe848SGuillaume Chatelet using make_big_int_unsigned_t = typename make_big_int_unsigned<T>::type; 112209efe848SGuillaume Chatelet 112309efe848SGuillaume Chatelet // make_big_int_signed 112409efe848SGuillaume Chatelet template <typename T> struct make_big_int_signed; 112509efe848SGuillaume Chatelet 112609efe848SGuillaume Chatelet template <size_t Bits, bool Signed, typename T> 112709efe848SGuillaume Chatelet struct make_big_int_signed<BigInt<Bits, Signed, T>> 112809efe848SGuillaume Chatelet : cpp::type_identity<BigInt<Bits, true, T>> {}; 112909efe848SGuillaume Chatelet 113009efe848SGuillaume Chatelet template <typename T> 113109efe848SGuillaume Chatelet using make_big_int_signed_t = typename make_big_int_signed<T>::type; 113209efe848SGuillaume Chatelet 113309efe848SGuillaume Chatelet // make_integral_or_big_int_unsigned 113409efe848SGuillaume Chatelet template <typename T, class = void> struct make_integral_or_big_int_unsigned; 113509efe848SGuillaume Chatelet 113609efe848SGuillaume Chatelet template <typename T> 113709efe848SGuillaume Chatelet struct make_integral_or_big_int_unsigned< 113809efe848SGuillaume Chatelet T, cpp::enable_if_t<cpp::is_integral_v<T>>> : cpp::make_unsigned<T> {}; 113909efe848SGuillaume Chatelet 114009efe848SGuillaume Chatelet template <typename T> 114109efe848SGuillaume Chatelet struct make_integral_or_big_int_unsigned<T, cpp::enable_if_t<is_big_int_v<T>>> 114209efe848SGuillaume Chatelet : make_big_int_unsigned<T> {}; 114309efe848SGuillaume Chatelet 114409efe848SGuillaume Chatelet template <typename T> 114509efe848SGuillaume Chatelet using make_integral_or_big_int_unsigned_t = 114609efe848SGuillaume Chatelet typename make_integral_or_big_int_unsigned<T>::type; 114709efe848SGuillaume Chatelet 114809efe848SGuillaume Chatelet // make_integral_or_big_int_signed 114909efe848SGuillaume Chatelet template <typename T, class = void> struct make_integral_or_big_int_signed; 115009efe848SGuillaume Chatelet 115109efe848SGuillaume Chatelet template <typename T> 115209efe848SGuillaume Chatelet struct make_integral_or_big_int_signed<T, 115309efe848SGuillaume Chatelet cpp::enable_if_t<cpp::is_integral_v<T>>> 115409efe848SGuillaume Chatelet : cpp::make_signed<T> {}; 115509efe848SGuillaume Chatelet 115609efe848SGuillaume Chatelet template <typename T> 115709efe848SGuillaume Chatelet struct make_integral_or_big_int_signed<T, cpp::enable_if_t<is_big_int_v<T>>> 115809efe848SGuillaume Chatelet : make_big_int_signed<T> {}; 115909efe848SGuillaume Chatelet 116009efe848SGuillaume Chatelet template <typename T> 116109efe848SGuillaume Chatelet using make_integral_or_big_int_signed_t = 116209efe848SGuillaume Chatelet typename make_integral_or_big_int_signed<T>::type; 116309efe848SGuillaume Chatelet 1164f3aceeeeSOverMighty // is_unsigned_integral_or_big_int 1165f3aceeeeSOverMighty template <typename T> 1166f3aceeeeSOverMighty struct is_unsigned_integral_or_big_int 1167f3aceeeeSOverMighty : cpp::bool_constant< 1168f3aceeeeSOverMighty cpp::is_same_v<T, make_integral_or_big_int_unsigned_t<T>>> {}; 1169f3aceeeeSOverMighty 1170f3aceeeeSOverMighty template <typename T> 1171f3aceeeeSOverMighty // Meant to look like <type_traits> helper variable templates. 1172f3aceeeeSOverMighty // NOLINTNEXTLINE(readability-identifier-naming) 1173f3aceeeeSOverMighty LIBC_INLINE_VAR constexpr bool is_unsigned_integral_or_big_int_v = 1174f3aceeeeSOverMighty is_unsigned_integral_or_big_int<T>::value; 1175f3aceeeeSOverMighty 117609efe848SGuillaume Chatelet namespace cpp { 117709efe848SGuillaume Chatelet 117809efe848SGuillaume Chatelet // Specialization of cpp::bit_cast ('bit.h') from T to BigInt. 117909efe848SGuillaume Chatelet template <typename To, typename From> 118009efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t< 118109efe848SGuillaume Chatelet (sizeof(To) == sizeof(From)) && cpp::is_trivially_copyable<To>::value && 118209efe848SGuillaume Chatelet cpp::is_trivially_copyable<From>::value && is_big_int<To>::value, 118309efe848SGuillaume Chatelet To> 118409efe848SGuillaume Chatelet bit_cast(const From &from) { 118509efe848SGuillaume Chatelet To out; 118609efe848SGuillaume Chatelet using Storage = decltype(out.val); 118709efe848SGuillaume Chatelet out.val = cpp::bit_cast<Storage>(from); 118809efe848SGuillaume Chatelet return out; 118909efe848SGuillaume Chatelet } 119009efe848SGuillaume Chatelet 119109efe848SGuillaume Chatelet // Specialization of cpp::bit_cast ('bit.h') from BigInt to T. 119209efe848SGuillaume Chatelet template <typename To, size_t Bits> 119309efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t< 119409efe848SGuillaume Chatelet sizeof(To) == sizeof(UInt<Bits>) && 119509efe848SGuillaume Chatelet cpp::is_trivially_constructible<To>::value && 119609efe848SGuillaume Chatelet cpp::is_trivially_copyable<To>::value && 119709efe848SGuillaume Chatelet cpp::is_trivially_copyable<UInt<Bits>>::value, 119809efe848SGuillaume Chatelet To> 119909efe848SGuillaume Chatelet bit_cast(const UInt<Bits> &from) { 120009efe848SGuillaume Chatelet return cpp::bit_cast<To>(from.val); 120109efe848SGuillaume Chatelet } 120209efe848SGuillaume Chatelet 120309efe848SGuillaume Chatelet // Specialization of cpp::popcount ('bit.h') for BigInt. 120409efe848SGuillaume Chatelet template <typename T> 120509efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 120609efe848SGuillaume Chatelet popcount(T value) { 120709efe848SGuillaume Chatelet int bits = 0; 120809efe848SGuillaume Chatelet for (auto word : value.val) 120909efe848SGuillaume Chatelet if (word) 121009efe848SGuillaume Chatelet bits += popcount(word); 121109efe848SGuillaume Chatelet return bits; 121209efe848SGuillaume Chatelet } 121309efe848SGuillaume Chatelet 121409efe848SGuillaume Chatelet // Specialization of cpp::has_single_bit ('bit.h') for BigInt. 121509efe848SGuillaume Chatelet template <typename T> 121609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, bool> 121709efe848SGuillaume Chatelet has_single_bit(T value) { 121809efe848SGuillaume Chatelet int bits = 0; 121909efe848SGuillaume Chatelet for (auto word : value.val) { 122009efe848SGuillaume Chatelet if (word == 0) 122109efe848SGuillaume Chatelet continue; 122209efe848SGuillaume Chatelet bits += popcount(word); 122309efe848SGuillaume Chatelet if (bits > 1) 122409efe848SGuillaume Chatelet return false; 122509efe848SGuillaume Chatelet } 122609efe848SGuillaume Chatelet return bits == 1; 122709efe848SGuillaume Chatelet } 122809efe848SGuillaume Chatelet 122909efe848SGuillaume Chatelet // Specialization of cpp::countr_zero ('bit.h') for BigInt. 123009efe848SGuillaume Chatelet template <typename T> 123109efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 123209efe848SGuillaume Chatelet countr_zero(const T &value) { 123309efe848SGuillaume Chatelet return multiword::countr_zero(value.val); 123409efe848SGuillaume Chatelet } 123509efe848SGuillaume Chatelet 123609efe848SGuillaume Chatelet // Specialization of cpp::countl_zero ('bit.h') for BigInt. 123709efe848SGuillaume Chatelet template <typename T> 123809efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 123909efe848SGuillaume Chatelet countl_zero(const T &value) { 124009efe848SGuillaume Chatelet return multiword::countl_zero(value.val); 124109efe848SGuillaume Chatelet } 124209efe848SGuillaume Chatelet 124309efe848SGuillaume Chatelet // Specialization of cpp::countl_one ('bit.h') for BigInt. 124409efe848SGuillaume Chatelet template <typename T> 124509efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 124609efe848SGuillaume Chatelet countl_one(T value) { 124709efe848SGuillaume Chatelet return multiword::countl_one(value.val); 124809efe848SGuillaume Chatelet } 124909efe848SGuillaume Chatelet 125009efe848SGuillaume Chatelet // Specialization of cpp::countr_one ('bit.h') for BigInt. 125109efe848SGuillaume Chatelet template <typename T> 125209efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 125309efe848SGuillaume Chatelet countr_one(T value) { 125409efe848SGuillaume Chatelet return multiword::countr_one(value.val); 125509efe848SGuillaume Chatelet } 125609efe848SGuillaume Chatelet 125709efe848SGuillaume Chatelet // Specialization of cpp::bit_width ('bit.h') for BigInt. 125809efe848SGuillaume Chatelet template <typename T> 125909efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 126009efe848SGuillaume Chatelet bit_width(T value) { 126109efe848SGuillaume Chatelet return cpp::numeric_limits<T>::digits - cpp::countl_zero(value); 126209efe848SGuillaume Chatelet } 126309efe848SGuillaume Chatelet 126409efe848SGuillaume Chatelet // Forward-declare rotr so that rotl can use it. 126509efe848SGuillaume Chatelet template <typename T> 126609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> 126709efe848SGuillaume Chatelet rotr(T value, int rotate); 126809efe848SGuillaume Chatelet 126909efe848SGuillaume Chatelet // Specialization of cpp::rotl ('bit.h') for BigInt. 127009efe848SGuillaume Chatelet template <typename T> 127109efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> 127209efe848SGuillaume Chatelet rotl(T value, int rotate) { 127309efe848SGuillaume Chatelet constexpr unsigned N = cpp::numeric_limits<T>::digits; 127409efe848SGuillaume Chatelet rotate = rotate % N; 127509efe848SGuillaume Chatelet if (!rotate) 127609efe848SGuillaume Chatelet return value; 127709efe848SGuillaume Chatelet if (rotate < 0) 127809efe848SGuillaume Chatelet return cpp::rotr<T>(value, -rotate); 127909efe848SGuillaume Chatelet return (value << rotate) | (value >> (N - rotate)); 128009efe848SGuillaume Chatelet } 128109efe848SGuillaume Chatelet 128209efe848SGuillaume Chatelet // Specialization of cpp::rotr ('bit.h') for BigInt. 128309efe848SGuillaume Chatelet template <typename T> 128409efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> 128509efe848SGuillaume Chatelet rotr(T value, int rotate) { 128609efe848SGuillaume Chatelet constexpr unsigned N = cpp::numeric_limits<T>::digits; 128709efe848SGuillaume Chatelet rotate = rotate % N; 128809efe848SGuillaume Chatelet if (!rotate) 128909efe848SGuillaume Chatelet return value; 129009efe848SGuillaume Chatelet if (rotate < 0) 129109efe848SGuillaume Chatelet return cpp::rotl<T>(value, -rotate); 129209efe848SGuillaume Chatelet return (value >> rotate) | (value << (N - rotate)); 129309efe848SGuillaume Chatelet } 129409efe848SGuillaume Chatelet 129509efe848SGuillaume Chatelet } // namespace cpp 129609efe848SGuillaume Chatelet 129709efe848SGuillaume Chatelet // Specialization of mask_trailing_ones ('math_extras.h') for BigInt. 129809efe848SGuillaume Chatelet template <typename T, size_t count> 129909efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> 130009efe848SGuillaume Chatelet mask_trailing_ones() { 130109efe848SGuillaume Chatelet static_assert(!T::SIGNED && count <= T::BITS); 130209efe848SGuillaume Chatelet if (count == T::BITS) 130309efe848SGuillaume Chatelet return T::all_ones(); 130409efe848SGuillaume Chatelet constexpr size_t QUOTIENT = count / T::WORD_SIZE; 130509efe848SGuillaume Chatelet constexpr size_t REMAINDER = count % T::WORD_SIZE; 130609efe848SGuillaume Chatelet T out; // zero initialized 130709efe848SGuillaume Chatelet for (size_t i = 0; i <= QUOTIENT; ++i) 130809efe848SGuillaume Chatelet out[i] = i < QUOTIENT 130909efe848SGuillaume Chatelet ? -1 131009efe848SGuillaume Chatelet : mask_trailing_ones<typename T::word_type, REMAINDER>(); 131109efe848SGuillaume Chatelet return out; 131209efe848SGuillaume Chatelet } 131309efe848SGuillaume Chatelet 131409efe848SGuillaume Chatelet // Specialization of mask_leading_ones ('math_extras.h') for BigInt. 131509efe848SGuillaume Chatelet template <typename T, size_t count> 131609efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> mask_leading_ones() { 131709efe848SGuillaume Chatelet static_assert(!T::SIGNED && count <= T::BITS); 131809efe848SGuillaume Chatelet if (count == T::BITS) 131909efe848SGuillaume Chatelet return T::all_ones(); 132009efe848SGuillaume Chatelet constexpr size_t QUOTIENT = (T::BITS - count - 1U) / T::WORD_SIZE; 132109efe848SGuillaume Chatelet constexpr size_t REMAINDER = count % T::WORD_SIZE; 132209efe848SGuillaume Chatelet T out; // zero initialized 132309efe848SGuillaume Chatelet for (size_t i = QUOTIENT; i < T::WORD_COUNT; ++i) 132409efe848SGuillaume Chatelet out[i] = i > QUOTIENT 132509efe848SGuillaume Chatelet ? -1 132609efe848SGuillaume Chatelet : mask_leading_ones<typename T::word_type, REMAINDER>(); 132709efe848SGuillaume Chatelet return out; 132809efe848SGuillaume Chatelet } 132909efe848SGuillaume Chatelet 133009efe848SGuillaume Chatelet // Specialization of mask_trailing_zeros ('math_extras.h') for BigInt. 133109efe848SGuillaume Chatelet template <typename T, size_t count> 133209efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> 133309efe848SGuillaume Chatelet mask_trailing_zeros() { 133409efe848SGuillaume Chatelet return mask_leading_ones<T, T::BITS - count>(); 133509efe848SGuillaume Chatelet } 133609efe848SGuillaume Chatelet 133709efe848SGuillaume Chatelet // Specialization of mask_leading_zeros ('math_extras.h') for BigInt. 133809efe848SGuillaume Chatelet template <typename T, size_t count> 133909efe848SGuillaume Chatelet LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> 134009efe848SGuillaume Chatelet mask_leading_zeros() { 134109efe848SGuillaume Chatelet return mask_trailing_ones<T, T::BITS - count>(); 134209efe848SGuillaume Chatelet } 134309efe848SGuillaume Chatelet 134409efe848SGuillaume Chatelet // Specialization of count_zeros ('math_extras.h') for BigInt. 134509efe848SGuillaume Chatelet template <typename T> 134609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 134709efe848SGuillaume Chatelet count_zeros(T value) { 134809efe848SGuillaume Chatelet return cpp::popcount(~value); 134909efe848SGuillaume Chatelet } 135009efe848SGuillaume Chatelet 135109efe848SGuillaume Chatelet // Specialization of first_leading_zero ('math_extras.h') for BigInt. 135209efe848SGuillaume Chatelet template <typename T> 135309efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 135409efe848SGuillaume Chatelet first_leading_zero(T value) { 135509efe848SGuillaume Chatelet return value == cpp::numeric_limits<T>::max() ? 0 135609efe848SGuillaume Chatelet : cpp::countl_one(value) + 1; 135709efe848SGuillaume Chatelet } 135809efe848SGuillaume Chatelet 135909efe848SGuillaume Chatelet // Specialization of first_leading_one ('math_extras.h') for BigInt. 136009efe848SGuillaume Chatelet template <typename T> 136109efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 136209efe848SGuillaume Chatelet first_leading_one(T value) { 136309efe848SGuillaume Chatelet return first_leading_zero(~value); 136409efe848SGuillaume Chatelet } 136509efe848SGuillaume Chatelet 136609efe848SGuillaume Chatelet // Specialization of first_trailing_zero ('math_extras.h') for BigInt. 136709efe848SGuillaume Chatelet template <typename T> 136809efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 136909efe848SGuillaume Chatelet first_trailing_zero(T value) { 137009efe848SGuillaume Chatelet return value == cpp::numeric_limits<T>::max() ? 0 137109efe848SGuillaume Chatelet : cpp::countr_zero(~value) + 1; 137209efe848SGuillaume Chatelet } 137309efe848SGuillaume Chatelet 137409efe848SGuillaume Chatelet // Specialization of first_trailing_one ('math_extras.h') for BigInt. 137509efe848SGuillaume Chatelet template <typename T> 137609efe848SGuillaume Chatelet [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> 137709efe848SGuillaume Chatelet first_trailing_one(T value) { 137809efe848SGuillaume Chatelet return value == cpp::numeric_limits<T>::max() ? 0 137909efe848SGuillaume Chatelet : cpp::countr_zero(value) + 1; 138009efe848SGuillaume Chatelet } 138109efe848SGuillaume Chatelet 13825ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 138309efe848SGuillaume Chatelet 138421895a84SOleksandr T. #endif // LLVM_LIBC_SRC___SUPPORT_BIG_INT_H 1385