31#ifndef AEU_MULTIPRECISION
32#define AEU_MULTIPRECISION
42#define gpu __host__ __device__
43 #include <cuda/std/utility>
44 #include <cuda/std/array>
53#if defined AESI_UNSAFE
54 #warning Enabled nightly mode for the library. Functions and methods input arguments are not checked for validity. Be really gentle
58#ifdef AESI_GMP_INTEGRATION
64 using block = uint32_t;
66 constexpr inline std::size_t bitsInByte = 8;
67 constexpr inline std::size_t blockBitLength =
sizeof(block) * bitsInByte;
68 constexpr inline uint64_t blockBase = 1ULL << blockBitLength;
69 constexpr inline block blockMax = 0xff'ff'ff'ffu;
75 enum class Comparison { equal = 0, less = 1, greater = 2, equivalent = 3 };
83template <std::
size_t bitness = 512>
requires (bitness % blockBitLength == 0)
85 static_assert(bitness >
sizeof(uint64_t),
"Use built-in types for numbers 64-bit or less.");
87 static constexpr std::size_t blocksNumber = bitness / blockBitLength;
90 template <
typename T1,
typename T2>
91 using pair = cuda::std::pair<T1, T2>;
92 using blockLine = cuda::std::array<block, blocksNumber>;
94 template<
typename T1,
typename T2>
95 using pair = std::pair<T1, T2>;
96 using blockLine = std::array<block, blocksNumber>;
113 gpu
static constexpr auto addLine(blockLine& dst,
const blockLine& src)
noexcept -> uint64_t {
114 uint64_t carryOut = 0;
115 for (std::size_t i = 0; i < blocksNumber; ++i) {
116 uint64_t sum =
static_cast<uint64_t
>(dst[i]) +
static_cast<uint64_t
>(src[i]) + carryOut;
117 carryOut = sum / blockBase; dst[i] =
static_cast<block
>(sum % blockBase);
127 gpu
static constexpr auto makeComplement(blockLine& line)
noexcept -> uint64_t {
128 uint64_t carryOut = 1;
129 for(std::size_t i = 0; i < blocksNumber; ++i) {
130 const uint64_t sum = blockBase - 1ULL -
static_cast<uint64_t
>(line[i]) + carryOut;
131 carryOut = sum / blockBase; line[i] =
static_cast<block
>(sum % blockBase);
142 constexpr Aeu() noexcept = default;
147 constexpr ~
Aeu() noexcept = default;
152 constexpr
Aeu(const
Aeu& copy) noexcept = default;
158 constexpr
Aeu& operator=(const
Aeu& other) = default;
166 template <typename Integral> requires (std::is_unsigned_v<Integral>)
167 gpu constexpr
Aeu(Integral value) noexcept {
169 unsigned long long tValue =
static_cast<unsigned long long>(value);
170 for (std::size_t i = 0; i < blocksNumber; ++i) {
171 blocks[i] =
static_cast<block
>(tValue % blockBase);
184 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
185 gpu
constexpr Aeu(
const Char* data, std::size_t size) noexcept :
Aeu {} {
186 if(size == 0)
return;
188 std::size_t position = 0;
190 if constexpr (std::is_same_v<Char, char>) {
191 for(; position < size && !std::isalnum(data[position]); ++position) ;
193 for(; position < size && !std::iswalnum(static_cast<wint_t>(data[position])); ++position) ;
199 const auto base = [&data, &size, &position] {
200 if (data[position] == Char(
'0') && size > position + 1) {
201 switch (data[position + 1]) {
202 case Char(
'b'): case Char(
'B'):
203 position += 2;
return 2u;
204 case Char(
'o'): case Char(
'O'):
205 position += 2;
return 8u;
206 case Char(
'x'): case Char(
'X'):
207 position += 2;
return 16u;
214 for(; position < size; ++position) {
215 const auto digit = [] (Char ch) {
216 if(Char(
'0') <= ch && ch <= Char(
'9'))
217 return static_cast<unsigned>(ch) -
static_cast<unsigned>(Char(
'0'));
218 if(Char(
'a') <= ch && ch <= Char(
'f'))
219 return static_cast<unsigned>(ch) -
static_cast<unsigned>(Char(
'a')) + 10u;
220 if(Char(
'A') <= ch && ch <= Char(
'F'))
221 return static_cast<unsigned>(ch) -
static_cast<unsigned>(Char(
'A')) + 10u;
237 template <
typename Char, std::
size_t arrayLength>
requires (arrayLength > 1 && (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>))
238 gpu
constexpr Aeu(
const Char (&literal)[arrayLength]) noexcept :
Aeu(literal, arrayLength) {}
245 template <
typename String,
typename Char =
typename String::value_type>
requires (std::is_same_v<std::basic_string<Char>,
246 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
247 gpu
constexpr Aeu(String&& stringView) noexcept :
Aeu(stringView.data(), stringView.size()) {}
249 template <
typename String,
typename Char =
typename String::value_type>
requires (std::is_same_v<std::basic_string<Char>,
250 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
251 gpu
constexpr Aeu(
const String& stringView) noexcept :
Aeu(stringView.data(), stringView.size()) {}
253#ifdef AESI_GMP_INTEGRATION
258 constexpr Aeu(
const mpz_class& value) :
Aeu {} {
259 const auto bitLength = mpz_sizeinbase(value.get_mpz_t(), 2);
260 auto tBlocksNumber = 1 + (bitLength - 1) /
sizeof(block) * 8;
262 std::vector<block> buffer (tBlocksNumber, 0u);
263 mpz_export(buffer.data(), &tBlocksNumber, -1,
sizeof(block), -1, 0, value.get_mpz_t());
265 for (std::size_t i = 0; i < tBlocksNumber; ++i)
266 setBlock(i, buffer[i]);
288 Aeu result = *
this; makeComplement(result.blocks);
return result;
296 for(std::size_t i = 0; i < blocksNumber; ++i) {
297 if(blocks[i] < blockMax) {
300 }
else blocks[i] = 0u;
316 for(std::size_t i = 0; i < blocksNumber; ++i) {
320 blocks[i] = blockMax;
340 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>) [[nodiscard]]
341 gpu
constexpr friend auto operator+(
const Aeu& addition, Unsigned addendum)
noexcept ->
Aeu {
342 Aeu result = addition; result += addendum;
return result;
353 Aeu result = addition; result += addendum;
return result;
362 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>)
363 gpu
constexpr friend auto operator+=(
Aeu& addition, Unsigned addendum)
noexcept ->
Aeu& {
364 for(std::size_t i = 0; i < blocksNumber; ++i) {
365 const auto currentSum =
static_cast<uint64_t
>(addition.blocks[i]) +
static_cast<uint64_t
>(addendum);
366 addendum =
static_cast<Unsigned
>(currentSum / blockBase); addition.blocks[i] =
static_cast<block
>(currentSum % blockBase);
378 addLine(addition.blocks, addendum.blocks);
return addition;
392 Aeu result = subtraction; result -= subtrahend;
return result;
402 return subtraction += -subtrahend;
414 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>) [[nodiscard]]
415 gpu
constexpr friend auto operator*(
Aeu& multiplication, Unsigned factor)
noexcept ->
Aeu {
416 Aeu result = multiplication; result *= factor;
return result;
427 Aeu result = multiplication; result *= factor;
return result;
437 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>)
438 gpu
constexpr friend auto operator*=(
Aeu& multiplication, Unsigned factor)
noexcept ->
Aeu& {
439 if constexpr (std::is_same_v<Unsigned, uint64_t>) {
441 const auto smallerLength = (factor > blockMax ? 2UL : 1UL);
444 for(std::size_t i = 0; i < longerLength; ++i) {
445 const uint64_t tBlock = multiplication.blocks[i];
446 uint64_t carryOut = 0;
448 for(std::size_t j = 0; j < smallerLength && j < buffer.size() - i; ++j) {
449 const auto product = tBlock * (factor >> blockBitLength * j & 0x00'00'00'00'ff'ff'ff'ff) + carryOut;
450 const auto partial =
static_cast<uint64_t
>(buffer[i + j]) + product % blockBase;
451 carryOut = product / blockBase + partial / blockBase;
452 buffer[i + j] =
static_cast<block
>(partial % blockBase);
455 if(smallerLength + i < buffer.size())
456 buffer[smallerLength + i] +=
static_cast<block
>(carryOut);
459 multiplication.blocks = buffer;
460 return multiplication;
462 uint64_t carryOut = 0;
463 for (std::size_t i = 0; i < blocksNumber; ++i) {
464 const auto product =
static_cast<uint64_t
>(factor) *
static_cast<uint64_t
>(multiplication.blocks[i]) + carryOut;
465 multiplication.blocks[i] =
static_cast<block
>(product % blockBase); carryOut = product / blockBase;
467 return multiplication;
478 constexpr auto multiplyLines = [] (
const blockLine& longerLine,
const std::size_t longerLength,
479 const blockLine& smallerLine,
const std::size_t smallerLength) {
482 for(std::size_t i = 0; i < longerLength; ++i) {
483 const uint64_t tBlock = longerLine[i];
484 uint64_t carryOut = 0;
486 for(std::size_t j = 0; j < smallerLength && j < buffer.size() - i; ++j) {
487 const auto product = tBlock *
static_cast<uint64_t
>(smallerLine[j]) + carryOut;
488 const auto partial =
static_cast<uint64_t
>(buffer[i + j]) + product % blockBase;
489 carryOut = product / blockBase + partial / blockBase;
490 buffer[i + j] =
static_cast<block
>(partial % blockBase);
493 if(smallerLength < blocksNumber && smallerLength + i < buffer.size())
494 buffer[smallerLength + i] +=
static_cast<block
>(carryOut);
501 if(
const std::size_t valueLength = factor.filledBlocksNumber(); thisLength > valueLength)
502 multiplication.blocks = multiplyLines(multiplication.blocks, thisLength, factor.blocks, valueLength);
504 multiplication.blocks = multiplyLines(factor.blocks, valueLength, multiplication.blocks, thisLength);
506 return multiplication;
521 Aeu quotient, _; divide(division, divisor, quotient, _);
return quotient;
531 gpu
constexpr friend auto operator/=(
Aeu& division,
const Aeu& divisor)
noexcept ->
Aeu& {
return division = division / divisor; }
544 Aeu _, remainder; divide(modulation, modulo, _, remainder);
return remainder;
554 return modulation = modulation % modulo;
568 for(std::size_t i = 0; i < blocksNumber; ++i)
569 result.blocks[i] = ~blocks[i];
581 Aeu result = left; result ^= right;
return result;
591 for(std::size_t i = 0; i < blocksNumber; ++i)
592 left.blocks[i] ^= right.blocks[i];
604 Aeu result = left; result &= right;
return result;
614 for(std::size_t i = 0; i < blocksNumber; ++i)
615 left.blocks[i] &= right.blocks[i];
627 Aeu result = left; result |= right;
return result;
637 for(std::size_t i = 0; i < blocksNumber; ++i)
638 left.blocks[i] |= right.blocks[i];
649 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>) [[nodiscard]]
650 gpu
constexpr friend auto operator<<(
const Aeu& value, Unsigned bitShift)
noexcept ->
Aeu {
651 Aeu result = value; result <<= bitShift;
return result;
661 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>)
662 gpu
constexpr friend auto operator<<=(
Aeu& value, Unsigned bitShift)
noexcept ->
Aeu& {
663 if(bitShift >= bitness || bitShift == 0)
return value;
665 const std::size_t quotient = bitShift / blockBitLength, remainder = bitShift % blockBitLength;
666 const block stamp =
static_cast<block
>((1ULL << (blockBitLength - remainder)) - 1);
668 const std::size_t minI = quotient + (remainder ? 1U : 0U);
669 for (std::size_t i = blocksNumber; i-- > minI;)
670 value.blocks[i] = (value.blocks[i - quotient] & stamp) << remainder
671 | ((value.blocks[i - quotient - (remainder ? 1U : 0U)] & ~stamp) >> (blockBitLength - remainder) % blockBitLength);
673 value.blocks[quotient] = (value.blocks[0] & stamp) << remainder;
675 for (std::size_t i = 0; i < quotient; ++i)
687 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>) [[nodiscard]]
688 gpu
constexpr friend auto operator>>(
const Aeu& value, Unsigned bitShift)
noexcept ->
Aeu {
689 Aeu result = value; result >>= bitShift;
return result;
699 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>)
700 gpu
constexpr friend auto operator>>=(
Aeu& value, Unsigned bitShift)
noexcept ->
Aeu& {
701 if(bitShift >= bitness || bitShift == 0)
return value;
703 const std::size_t quotient = bitShift / blockBitLength, remainder = bitShift % blockBitLength;
704 const block stamp =
static_cast<block
>((1ULL << remainder) - 1);
706 for(std::size_t i = 0; i < blocksNumber - (quotient + (remainder ? 1 : 0)); ++i)
707 value.blocks[i] = ((value.blocks[i + quotient + (remainder ? 1 : 0)] & stamp) << (blockBitLength - remainder) % blockBitLength) | (value.blocks[i + quotient] & ~stamp) >> remainder;
709 value.blocks[blocksNumber - 1 - quotient] = (value.blocks[blocksNumber - 1] & ~stamp) >> remainder;
711 for(std::size_t i = blocksNumber - quotient; i < blocksNumber; ++i)
726 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned> &&
sizeof(Unsigned) < 8)
727 gpu
constexpr friend auto operator==(
const Aeu& our, Unsigned other)
noexcept ->
bool {
730 gpu
constexpr friend auto operator==(
const Aeu& our, uint64_t other)
noexcept ->
bool {
731 return our.
filledBlocksNumber() <= 2 && (
static_cast<uint64_t
>(our.blocks[1]) << blockBitLength |
static_cast<uint64_t
>(our.blocks[0])) == other;
740 template <std::
size_t otherBitness>
742 return our.
compareTo(other) == Comparison::equal;
745#ifdef AESI_GMP_INTEGRATION
752 template <
typename T,
typename U>
753 constexpr friend auto operator==(
const Aeu& our,
const __gmp_expr<T, U>& other)
noexcept ->
bool {
754 return our ==
Aeu(mpz_class(other));
767 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned> &&
sizeof(Unsigned) < 8) [[nodiscard]]
768 gpu
constexpr auto compareTo(Unsigned other)
const noexcept -> Comparison {
769 using enum Comparison;
771 if(filledBlocksNumber() > 1)
return greater;
772 const auto cmp =
static_cast<block
>(other);
790 gpu
constexpr auto compareTo(uint64_t other)
const noexcept -> Comparison {
791 using enum Comparison;
792 if(filledBlocksNumber() > 2)
return greater;
793 const auto base = (
static_cast<uint64_t
>(blocks[1]) << blockBitLength) |
static_cast<uint64_t
>(blocks[0]);
795 return greater;
else if(base < other)
return less;
else return equal;
804 template <std::
size_t otherBitness = bitness> [[nodiscard]]
806 using enum Comparison;
808 const auto lowerBlockBorder = (blocksNumber < other.totalBlocksNumber() ? blocksNumber : other.totalBlocksNumber());
809 for(std::size_t i = lowerBlockBorder; i-- > 0;) {
810 const block thisBlock = blocks[i], otherBlock = other.getBlock(i);
811 if(thisBlock != otherBlock)
812 return (thisBlock > otherBlock ? greater : less);
815 if constexpr (otherBitness != blocksNumber * blockBitLength) {
816 using enum Comparison;
817 if (other.totalBlocksNumber() > blocksNumber) {
818 for (std::size_t i = other.totalBlocksNumber(); i-- > lowerBlockBorder;)
819 if (other.getBlock(i) != 0)
821 }
else if (blocksNumber > other.totalBlocksNumber()) {
822 for (std::size_t i = blocksNumber; i-- > lowerBlockBorder;)
834#if (defined(__CUDACC__) || __cplusplus < 202002L || defined (PRE_CPP_20)) && !defined DOXYGEN_SKIP
838 gpu
constexpr auto operator!=(
const Aeu& value)
const noexcept ->
bool {
return !this->operator==(value); }
839 gpu
constexpr auto operator<(
const Aeu& value)
const noexcept ->
bool {
return this->compareTo(value) == Comparison::less; }
840 gpu
constexpr auto operator<=(
const Aeu& value)
const noexcept ->
bool {
return !this->operator>(value); }
841 gpu
constexpr auto operator>(
const Aeu& value)
const noexcept ->
bool {
return this->compareTo(value) == Comparison::greater; }
842 gpu
constexpr auto operator>=(
const Aeu& value)
const noexcept ->
bool {
return !this->operator<(value); }
850 gpu
constexpr auto operator<=>(
const Aeu& other)
const noexcept -> std::strong_ordering {
851 switch(this->compareTo(other)) {
852 using enum Comparison;
854 return std::strong_ordering::less;
856 return std::strong_ordering::greater;
858 return std::strong_ordering::equal;
860 return std::strong_ordering::equivalent;
870 template <
typename Un
signed>
871 gpu
constexpr auto operator<=>(
const Unsigned& other)
const noexcept -> std::strong_ordering {
872 switch(this->compareTo(other)) {
873 using enum Comparison;
875 return std::strong_ordering::less;
877 return std::strong_ordering::greater;
879 return std::strong_ordering::equal;
881 return std::strong_ordering::equivalent;
896 gpu
constexpr auto setBit(std::size_t index,
bool bit)
noexcept ->
void {
898 if(index >= bitness)
return;
900 const std::size_t blockNumber = index / blockBitLength, bitNumber = index % blockBitLength;
901 assert(blockNumber < blocksNumber && bitNumber < blockBitLength);
903 blocks[blockNumber] |= (1U << bitNumber);
905 blocks[blockNumber] &= (~(1U << bitNumber));
915 gpu
constexpr auto getBit(std::size_t index)
const noexcept ->
bool {
917 if(index >= bitness)
return false;
919 const std::size_t blockNumber = index / blockBitLength, bitNumber = index % blockBitLength;
920 assert(blockNumber < blocksNumber && bitNumber < blockBitLength);
921 return blocks[blockNumber] & (1U << bitNumber);
930 gpu
constexpr auto setByte(std::size_t index,
byte byte)
noexcept ->
void {
932 if(index > blocksNumber *
sizeof(block))
return;
934 const std::size_t blockNumber = index /
sizeof(block), byteInBlock = index %
sizeof(block), shift = byteInBlock * bitsInByte;
935 assert(blockNumber < blocksNumber && byteInBlock <
sizeof(block));
936 blocks[blockNumber] &= ~(0xffU << shift); blocks[blockNumber] |=
static_cast<block
>(byte) << shift;
946 gpu
constexpr auto getByte(std::size_t index)
const noexcept ->
byte {
948 if(index > blocksNumber *
sizeof(block))
return 0;
950 const std::size_t blockNumber = index /
sizeof(block), byteInBlock = index %
sizeof(block), shift = byteInBlock * bitsInByte;
951 assert(blockNumber < blocksNumber && byteInBlock <
sizeof(block));
952 return static_cast<byte>((blocks[blockNumber] & (0xffU << shift)) >> shift);
961 gpu
constexpr auto setBlock(std::size_t index, block block)
noexcept ->
void {
963 if(index >= blocksNumber)
return;
965 blocks[index] = block;
975 gpu
constexpr auto getBlock(std::size_t index)
const noexcept -> block {
977 if(index >= blocksNumber)
return block();
979 return blocks[index];
987 gpu
constexpr auto byteCount() const noexcept -> std::
size_t {
988 std::size_t lastBlock = blocksNumber - 1;
989 for(; lastBlock > 0 && blocks[lastBlock] == 0; --lastBlock)
992 for(std::size_t byteN =
sizeof(block); byteN-- > 0;) {
993 if((blocks[lastBlock] & (0xffU << (byteN * bitsInByte))) >> (byteN * bitsInByte))
994 return lastBlock *
sizeof(block) + byteN + 1;
996 return lastBlock *
sizeof(block);
1004 gpu
constexpr auto bitCount() const noexcept -> std::
size_t {
1005 std::size_t lastBlock = blocksNumber - 1;
1006 for(; lastBlock > 0 && blocks[lastBlock] == 0; --lastBlock)
1009 for(std::size_t byteN =
sizeof(block); byteN-- > 0;) {
1010 const auto byte = (blocks[lastBlock] & (0xffU << (byteN * bitsInByte))) >> (byteN * bitsInByte);
1013 for(std::size_t bitN = bitsInByte; bitN-- > 0;) {
1014 if((
byte & (0x1u << bitN)) >> bitN)
1015 return (lastBlock *
sizeof(block) + byteN) * bitsInByte + bitN + 1;
1017 return ((lastBlock - 1) *
sizeof(block) + byteN) * bitsInByte;
1019 return lastBlock *
sizeof(block);
1027 gpu
constexpr auto isOdd() const noexcept ->
bool {
return (0x1 & blocks[0]) == 1; }
1034 gpu
constexpr auto isEven() const noexcept ->
bool {
return (0x1 & blocks[0]) == 0; }
1041 gpu
constexpr auto isZero() const noexcept ->
bool {
return filledBlocksNumber() == 0; }
1049 for(std::size_t i = blocksNumber; i-- > 0;)
1050 if(blocks[i])
return i + 1;
1059 gpu
static constexpr auto getBitness() noexcept -> std::
size_t {
return bitness; }
1072 gpu
constexpr auto swap(
Aeu& other)
noexcept ->
void {
1073 Aeu t = other; other.operator=(*this); this->operator=(t);
1087 gpu
static constexpr auto divide(
const Aeu& number,
const Aeu& divisor,
Aeu& quotient,
Aeu& remainder)
noexcept ->
void {
1088 const auto ratio = number.compareTo(divisor);
1090 quotient =
Aeu {}; remainder =
Aeu {};
1092 if(ratio == Comparison::greater) {
1093 const auto bitsUsed = number.filledBlocksNumber() * blockBitLength;
1094 for(std::size_t i = bitsUsed; i-- > 0;) {
1096 remainder.setBit(0, number.getBit(i));
1098 if(remainder >= divisor) {
1099 remainder -= divisor;
1100 quotient.setBit(i,
true);
1103 }
else if(ratio == Comparison::less)
1104 remainder = number;
else quotient = 1u;
1114 gpu
static constexpr auto divide(
const Aeu& number,
const Aeu& divisor)
noexcept -> pair<Aeu, Aeu> {
1115 pair<Aeu, Aeu> results; divide(number, divisor, results.first, results.second);
return results;
1127 gpu
static constexpr auto gcd(
const Aeu& first,
const Aeu& second,
Aeu& bezoutX,
Aeu& bezoutY)
noexcept ->
Aeu {
1128 Aeu gcd, quotient, remainder;
1130 const auto ratio = first.
compareTo(second);
1131 if(ratio == Comparison::greater) {
1133 divide(first, second, quotient, remainder);
1136 divide(second, first, quotient, remainder);
1139 bezoutX = 0u; bezoutY = 1u;
1140 for(
Aeu tX = 1u, tY = 0u; remainder != 0u; ) {
1141 Aeu tGcd = gcd; gcd = remainder;
1143 Aeu t = bezoutX; bezoutX = tX - quotient * bezoutX; tX = t;
1144 t = bezoutY; bezoutY = tY - quotient * bezoutY; tY = t;
1146 divide(tGcd, gcd, quotient, remainder);
1149 if(ratio != Comparison::greater)
1150 bezoutX.swap(bezoutY);
1162 gpu
static constexpr auto gcd(
const Aeu& first,
const Aeu& second)
noexcept ->
Aeu {
1163 Aeu gcd, quotient, remainder;
1165 const auto ratio = first.
compareTo(second);
1166 if(ratio == Comparison::greater) {
1168 divide(first, second, quotient, remainder);
1171 divide(second, first, quotient, remainder);
1174 while(remainder != 0u) {
1175 Aeu tGcd = gcd; gcd = remainder;
1176 divide(tGcd, gcd, quotient, remainder);
1189 gpu
static constexpr auto lcm(
const Aeu& first,
const Aeu& second)
noexcept ->
Aeu {
return first / gcd(first, second) * second; }
1200 template <std::
size_t powerBitness = bitness> [[nodiscard]]
1208 auto [_, b] = divide(base, modulo);
1210 for(
unsigned iteration = 0; power.filledBlocksNumber() * blockBitLength != iteration; iteration++) {
1211 if(power.getBit(iteration)) {
1212 const auto [quotient, remainder] = divide(output * b, modulo);
1216 const auto [quotient, remainder] = divide(b * b, modulo);
1224 gpu
static constexpr auto powm(
const Aeu& base,
const Aeu& power,
const Aeu& mod)
noexcept ->
Aeu {
1226 auto [_, b] = divide(base, mod);
1228 for(std::size_t iteration = 0; power.filledBlocksNumber() * blockBitLength != iteration; iteration++) {
1229 if(power.getBit(iteration)) {
1230 const auto [quotient, remainder] = divide(output * b, mod);
1234 const auto [quotient, remainder] = divide(b * b, mod);
1248 gpu
static constexpr auto power2(std::size_t power)
noexcept ->
Aeu {
Aeu result {}; result.
setBit(power,
true);
return result; }
1257 Aeu x, y = power2((bitCount() + 1) / 2);
1261 y = (x + *
this / x) >> 1u;
1280 template <
byte base,
bool hexUppercase = false,
typename Char>
requires (std::is_same_v<Char, char> || (std::is_same_v<Char, wchar_t> && (base == 2 || base == 8 || base == 10 || base == 16)))
1281 gpu
constexpr auto getString(Char*
const buffer, std::size_t bufferSize,
bool showBase =
false)
const noexcept -> std::size_t {
1282 if(bufferSize < 2)
return 0;
1284 std::size_t position = 0;
1286 if (showBase && bufferSize > 3) {
1287 if constexpr (base == 2) {
1288 if constexpr (std::is_same_v<Char, char>) {
1289 buffer[0] =
'0'; buffer[1] =
'b';
1291 buffer[0] = L
'0'; buffer[1] = L
'b';
1294 }
else if constexpr (base == 8) {
1295 if constexpr (std::is_same_v<Char, char>) {
1296 buffer[0] =
'0'; buffer[1] =
'o';
1298 buffer[0] = L
'0'; buffer[1] = L
'o';
1301 }
else if constexpr (base == 16) {
1302 if constexpr (std::is_same_v<Char, char>) {
1303 buffer[0] =
'0'; buffer[1] =
'x';
1305 buffer[0] = L
'0'; buffer[1] = L
'x';
1312 buffer[position++] = [] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; }}();
1316 if constexpr (base == 16) {
1317 std::size_t iter = blocks.size() - 1;
1318 for (; iter > 0 && blocks[iter] == 0; --iter)
1321 if constexpr (std::is_same_v<Char, char>) {
1322 if constexpr (hexUppercase) {
1323 position +=
static_cast<std::size_t
>(snprintf(buffer + position, bufferSize - position,
"%X", blocks[iter]));
1325 position +=
static_cast<std::size_t
>(snprintf(buffer + position, bufferSize - position,
"%08X", blocks[iter]));
1327 position +=
static_cast<std::size_t
>(snprintf(buffer + position, bufferSize - position,
"%x", blocks[iter]));
1329 position +=
static_cast<std::size_t
>(snprintf(buffer + position, bufferSize - position,
"%08x", blocks[iter]));
1332 if constexpr (hexUppercase) {
1333 position +=
static_cast<std::size_t
>(swprintf(buffer + position, bufferSize - position, L
"%X", blocks[iter]));
1335 position +=
static_cast<std::size_t
>(swprintf(buffer + position, bufferSize - position, L
"%08X", blocks[iter]));
1337 position +=
static_cast<std::size_t
>(swprintf(buffer + position, bufferSize - position, L
"%x", blocks[iter]));
1339 position +=
static_cast<std::size_t
>(swprintf(buffer + position, bufferSize - position, L
"%08x", blocks[iter]));
1343 const auto startPosition = position;
1346 while (!copy.
isZero() && position < bufferSize) {
1347 auto [quotient, remainder] = divide(copy, base);
1348 if constexpr (std::is_same_v<Char, char>) {
1349 buffer[position++] =
static_cast<Char
>(
'0' + remainder.template integralCast<byte>());
1351 buffer[position++] =
static_cast<Char
>(L
'0' + remainder.template integralCast<byte>());
1355 const auto digitsTotal = position - startPosition;
1356 for (std::size_t i = 0; i * 2 < digitsTotal; ++i) {
1357 Char t = buffer[startPosition + i];
1358 buffer[startPosition + i] = buffer[startPosition + digitsTotal - 1 - i];
1359 buffer[startPosition + digitsTotal - 1 - i] = t;
1362 buffer[position++] = Char {};
1377 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1378 friend constexpr auto operator<<(std::basic_ostream<Char>& os,
const Aeu& number) -> std::basic_ostream<Char>& {
1379 auto flags = os.flags();
1381 const auto base = [] (
long baseField, std::basic_ostream<Char>& ss,
bool showbase) {
1382 auto tBase = (baseField == std::ios::hex ? 16u : (baseField == std::ios::oct ? 8u : 10u));
1383 if(showbase && tBase != 10)
1385 if constexpr (std::is_same_v<Char, char>) {
1386 return tBase == 8 ?
"0o" :
"0x";
1388 return tBase == 8 ? L
"0o" : L
"0x";
1390 } () << std::noshowbase ;
1392 } (flags & std::ios::basefield, os, flags & std::ios::showbase);
1398 std::size_t iter = number.blocks.size() - 1;
1399 for(; iter > 0 && number.blocks[iter] == 0; --iter)
1402 os << number.blocks[iter];
1403 for (; iter-- > 0;) {
1404 os.fill([] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; } } ());
1405 os.width(8); os << std::right << number.blocks[iter];
1410 constexpr auto bufferSize =
static_cast<std::size_t
>(
static_cast<double>(bitness) / 2.95);
1411 Char buffer [bufferSize] {}; std::size_t filled = 0;
1414 while(!copy.
isZero() && filled < bufferSize) {
1415 const auto [quotient, remainder] = divide(copy, base);
1416 buffer[filled++] =
static_cast<Char
>([] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; } } () + remainder.template integralCast<byte>());
1420 for(; filled > 0; --filled)
1421 os << buffer[filled - 1];
1436 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1437 constexpr auto readBinary(std::basic_istream<Char>& is,
bool bigEndian =
true) ->
void {
1440 for(
auto it = blocks.rbegin(); it != blocks.rend(); ++it)
1441 if(!is.read(
reinterpret_cast<char*
>(&*it),
sizeof(block)))
break;
1443 for(
auto& tBlock: blocks)
1444 if(!is.read(
reinterpret_cast<char*
>(&tBlock),
sizeof(block)))
break;
1455 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1456 constexpr auto writeBinary(std::basic_ostream<Char>& os,
bool bigEndian =
true)
const noexcept ->
void {
1458 for(
auto it = blocks.rbegin(); it != blocks.rend(); ++it)
1459 if(!os.write(
reinterpret_cast<const char*
>(&*it),
sizeof(block)))
break;
1461 for(
auto& block: blocks)
1462 if(!os.write(
reinterpret_cast<const char*
>(&block),
sizeof(block)))
break;
1474 template <
typename Integral>
requires (std::is_integral_v<Integral>) [[nodiscard]]
1476 const uint64_t value = (
static_cast<uint64_t
>(blocks[1]) << blockBitLength) |
static_cast<uint64_t
>(blocks[0]);
1477 return static_cast<Integral
>(value);
1488 template <std::
size_t newBitness>
requires (newBitness != bitness) [[nodiscard]]
1493 for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
1494 result.
setBlock(blockIdx, getBlock(blockIdx));
1501#if defined __CUDACC__
1509 __device__
constexpr auto tryAtomicSet(
const Aeu& value)
noexcept ->
void {
1510 for(std::size_t i = 0; i < blocksNumber; ++i)
1511 atomicExch(&blocks[i], value.blocks[i]);
1520 __device__
constexpr auto tryAtomicExchange(
const Aeu& value)
noexcept ->
void {
1521 for(std::size_t i = 0; i < blocksNumber; ++i)
1522 atomicExch(&value.blocks[i], atomicExch(&blocks[i], value.blocks[i]));
1592template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1601template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1610template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1619template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1628template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1637template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1646template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1655template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
Long precision unsigned integer.
Definition Aeu.h:84
static gpu constexpr auto gcd(const Aeu &first, const Aeu &second, Aeu &bezoutX, Aeu &bezoutY) noexcept -> Aeu
Extended Euclidean algorithm for greatest common divisor.
Definition Aeu.h:1127
gpu constexpr auto operator<=>(const Aeu &other) const noexcept -> std::strong_ordering
Three-way comparison operator.
Definition Aeu.h:850
gpu constexpr friend auto operator|=(Aeu &left, const Aeu &right) noexcept -> Aeu &
Assignment bitwise OR operator.
Definition Aeu.h:636
gpu constexpr auto bitCount() const noexcept -> std::size_t
Get amount of non-empty bits in number right to left.
Definition Aeu.h:1004
gpu constexpr friend auto operator&(const Aeu &left, const Aeu &right) noexcept -> Aeu
Bitwise AND operator.
Definition Aeu.h:603
gpu constexpr auto compareTo(Unsigned other) const noexcept -> Comparison
Internal comparison operator for built-in integral types uint8_t, uint16_t, uint32_t.
Definition Aeu.h:768
gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t
Get number of non-empty blocks inside object starting from the right.
Definition Aeu.h:1048
gpu constexpr auto operator+() const noexcept -> Aeu
Unary plus operator.
Definition Aeu.h:280
gpu constexpr friend auto operator/(const Aeu &division, const Aeu &divisor) noexcept -> Aeu
Division operator.
Definition Aeu.h:520
static gpu constexpr auto power2(std::size_t power) noexcept -> Aeu
Fast exponentiation for powers of 2.
Definition Aeu.h:1248
static gpu constexpr auto gcd(const Aeu &first, const Aeu &second) noexcept -> Aeu
Greatest common divisor.
Definition Aeu.h:1162
gpu constexpr auto isEven() const noexcept -> bool
Check whether number is even.
Definition Aeu.h:1034
gpu constexpr auto operator~() const noexcept -> Aeu
Bitwise complement operator.
Definition Aeu.h:566
gpu constexpr auto setByte(std::size_t index, byte byte) noexcept -> void
Set byte in number by index starting from the right.
Definition Aeu.h:930
gpu constexpr friend auto operator+(const Aeu &addition, const Aeu &addendum) noexcept -> Aeu
Addition operator.
Definition Aeu.h:352
gpu constexpr friend auto operator==(const Aeu &our, const Aeu< otherBitness > &other) noexcept -> bool
Templated Equality check operator for numbers of different precision.
Definition Aeu.h:741
gpu constexpr Aeu(String &&stringView) noexcept
String or string-view based constructor.
Definition Aeu.h:247
gpu constexpr friend auto operator%(const Aeu &modulation, const Aeu &modulo) noexcept -> Aeu
Modulo operator.
Definition Aeu.h:543
gpu constexpr auto byteCount() const noexcept -> std::size_t
Get amount of non-empty bytes in number right to left.
Definition Aeu.h:987
gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void
Set block in number by index starting from the right.
Definition Aeu.h:961
gpu constexpr friend auto operator&=(Aeu &left, const Aeu &right) noexcept -> Aeu &
Assignment bitwise AND operator.
Definition Aeu.h:613
gpu constexpr auto getByte(std::size_t index) const noexcept -> byte
Get byte in number by index starting from the right.
Definition Aeu.h:946
gpu constexpr Aeu(const Char(&literal)[arrayLength]) noexcept
C-style string literal constructor.
Definition Aeu.h:238
gpu constexpr auto operator--(int) &noexcept -> Aeu
Postfix decrement.
Definition Aeu.h:329
constexpr Aeu() noexcept=default
Default constructor.
static gpu constexpr auto powm(const Aeu &base, const Aeu< powerBitness > &power, const Aeu &modulo) noexcept -> Aeu
Exponentiation by modulo.
Definition Aeu.h:1201
gpu constexpr auto integralCast() const noexcept -> Integral
Integral type cast operator for built-in types.
Definition Aeu.h:1475
gpu constexpr friend auto operator-=(Aeu &subtraction, const Aeu &subtrahend) noexcept -> Aeu &
Assignment subtraction operator.
Definition Aeu.h:401
gpu constexpr auto isOdd() const noexcept -> bool
Check whether number is odd.
Definition Aeu.h:1027
gpu constexpr friend auto operator^=(Aeu &left, const Aeu &right) noexcept -> Aeu &
Assignment bitwise XOR operator.
Definition Aeu.h:590
constexpr auto writeBinary(std::basic_ostream< Char > &os, bool bigEndian=true) const noexcept -> void
STD stream binary writing operator.
Definition Aeu.h:1456
static gpu constexpr auto divide(const Aeu &number, const Aeu &divisor) noexcept -> pair< Aeu, Aeu >
Integer division. Returns results by value.
Definition Aeu.h:1114
gpu constexpr auto swap(Aeu &other) noexcept -> void
Make swap between two objects.
Definition Aeu.h:1072
static gpu constexpr auto divide(const Aeu &number, const Aeu &divisor, Aeu "ient, Aeu &remainder) noexcept -> void
Integer division. Returns results by reference.
Definition Aeu.h:1087
gpu constexpr auto operator++(int) &noexcept -> Aeu
Postfix increment.
Definition Aeu.h:309
static gpu constexpr auto getBitness() noexcept -> std::size_t
Get number's precision.
Definition Aeu.h:1059
gpu constexpr friend auto operator|(const Aeu &left, const Aeu &right) noexcept -> Aeu
Bitwise OR operator.
Definition Aeu.h:626
gpu constexpr friend auto operator^(const Aeu &left, const Aeu &right) noexcept -> Aeu
Bitwise XOR operator.
Definition Aeu.h:580
gpu constexpr auto setBit(std::size_t index, bool bit) noexcept -> void
Set a bit in number by index starting from the right.
Definition Aeu.h:896
gpu constexpr auto precisionCast() const noexcept -> Aeu< newBitness >
Precision cast operator.
Definition Aeu.h:1489
static gpu constexpr auto totalBlocksNumber() noexcept -> std::size_t
Get the number of blocks (length of array of uint32_t integers) inside object.
Definition Aeu.h:1066
gpu constexpr auto isZero() const noexcept -> bool
Check whether number is zero.
Definition Aeu.h:1041
gpu constexpr auto operator<=>(const Unsigned &other) const noexcept -> std::strong_ordering
Three-way comparison operator for numbers of different precision and built-in integral types.
Definition Aeu.h:871
gpu constexpr friend auto operator%=(Aeu &modulation, const Aeu &modulo) noexcept -> Aeu &
Assignment modulo operator.
Definition Aeu.h:553
gpu constexpr friend auto operator/=(Aeu &division, const Aeu &divisor) noexcept -> Aeu &
Assignment division operator.
Definition Aeu.h:531
gpu constexpr auto operator--() noexcept -> Aeu &
Prefix decrement.
Definition Aeu.h:315
constexpr auto readBinary(std::basic_istream< Char > &is, bool bigEndian=true) -> void
STD stream binary reading operator.
Definition Aeu.h:1437
gpu constexpr Aeu(const Char *data, std::size_t size) noexcept
Pointer-based character constructor.
Definition Aeu.h:185
gpu constexpr auto compareTo(uint64_t other) const noexcept -> Comparison
Internal comparison operator for type uint64_t.
Definition Aeu.h:790
gpu constexpr friend auto operator*=(Aeu &multiplication, const Aeu &factor) noexcept -> Aeu &
Assignment multiplication operator.
Definition Aeu.h:477
gpu constexpr friend auto operator+=(Aeu &addition, const Aeu &addendum) noexcept -> Aeu &
Assignment addition operator.
Definition Aeu.h:377
static gpu constexpr auto lcm(const Aeu &first, const Aeu &second) noexcept -> Aeu
Least common multiplier.
Definition Aeu.h:1189
gpu constexpr auto getBit(std::size_t index) const noexcept -> bool
Get bit in number by index staring from the right.
Definition Aeu.h:915
gpu constexpr friend auto operator-(const Aeu &subtraction, const Aeu &subtrahend) noexcept -> Aeu
Subtraction operator.
Definition Aeu.h:391
gpu constexpr auto squareRoot() const noexcept -> Aeu
Get square root.
Definition Aeu.h:1256
gpu constexpr auto getBlock(std::size_t index) const noexcept -> block
Get block in number by index starting from the right.
Definition Aeu.h:975
gpu constexpr friend auto operator*(const Aeu &multiplication, const Aeu &factor) noexcept -> Aeu
Multiplication operator.
Definition Aeu.h:426
gpu constexpr auto getString(Char *const buffer, std::size_t bufferSize, bool showBase=false) const noexcept -> std::size_t
Character buffer output operator.
Definition Aeu.h:1281
gpu constexpr auto operator-() const noexcept -> Aeu
Unary minus operator.
Definition Aeu.h:287
gpu constexpr auto operator++() noexcept -> Aeu &
Prefix increment.
Definition Aeu.h:295
gpu constexpr auto compareTo(const Aeu< otherBitness > &other) const noexcept -> Comparison
Internal comparison operator.
Definition Aeu.h:805