31#ifndef AEU_MULTIPRECISION
32#define AEU_MULTIPRECISION
39#define gpu __host__ __device__
40 #include <cuda/std/utility>
41 #include <cuda/std/array>
49#if defined AESI_UNSAFE
50 #warning Enabled nightly mode for the library. Functions and methods input arguments are not checked for validity. Be really gentle
53#ifdef AESI_CRYPTOPP_INTEGRATION
54#include <cryptopp/integer.h>
57#ifdef AESI_GMP_INTEGRATION
63 using block = uint32_t;
65 constexpr inline std::size_t bitsInByte = 8;
66 constexpr inline std::size_t blockBitLength =
sizeof(block) * bitsInByte;
67 constexpr inline uint64_t blockBase = 1ULL << blockBitLength;
68 constexpr inline block blockMax = 0xff'ff'ff'ffu;
74 enum class Comparison { equal = 0, less = 1, greater = 2, equivalent = 3 };
82template <std::
size_t bitness = 512>
requires (bitness % blockBitLength == 0)
84 static_assert(bitness >
sizeof(uint64_t),
"Use built-in types for numbers 64-bit or less.");
86 static constexpr std::size_t blocksNumber = bitness / blockBitLength;
89 template <
typename T1,
typename T2>
90 using pair = cuda::std::pair<T1, T2>;
91 using blockLine = cuda::std::array<block, blocksNumber>;
93 template<
typename T1,
typename T2>
94 using pair = std::pair<T1, T2>;
95 using blockLine = std::array<block, blocksNumber>;
112 gpu
static constexpr auto addLine(blockLine& dst,
const blockLine& src)
noexcept -> uint64_t {
113 uint64_t carryOut = 0;
114 for (std::size_t i = 0; i < blocksNumber; ++i) {
115 uint64_t sum =
static_cast<uint64_t
>(dst[i]) +
static_cast<uint64_t
>(src[i]) + carryOut;
116 carryOut = sum / blockBase; dst[i] =
static_cast<block
>(sum % blockBase);
126 gpu
static constexpr auto makeComplement(blockLine& line)
noexcept -> uint64_t {
127 uint64_t carryOut = 1;
128 for(std::size_t i = 0; i < blocksNumber; ++i) {
129 const uint64_t sum = blockBase - 1ULL -
static_cast<uint64_t
>(line[i]) + carryOut;
130 carryOut = sum / blockBase; line[i] =
static_cast<block
>(sum % blockBase);
141 gpu
constexpr Aeu() noexcept = default;
146 gpu constexpr ~
Aeu() noexcept = default;
151 gpu constexpr
Aeu(const
Aeu& copy) noexcept = default;
157 gpu constexpr
Aeu& operator=(const
Aeu& other) = default;
165 template <typename Integral> requires (std::is_unsigned_v<Integral>)
166 gpu constexpr
Aeu(Integral value) noexcept {
168 uint64_t tValue = (value < 0 ? static_cast<uint64_t>(value * -1) :
static_cast<uint64_t
>(value));
169 for (std::size_t i = 0; i < blocksNumber; ++i) {
170 blocks[i] =
static_cast<block
>(tValue % blockBase);
174 makeComplement(blocks);
185 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
186 gpu
constexpr Aeu(
const Char* data, std::size_t size) noexcept :
Aeu {} {
187 if(size == 0)
return;
189 constexpr const Char* characters = [] {
190 if constexpr (std::is_same_v<char, Char>) {
191 return "09aAfFoObBxX";
193 return L
"09aAfFoObBxX";
196 std::size_t position = 0;
198 if constexpr (std::is_same_v<Char, char>) {
199 for(; position < size && !std::isalnum(data[position]); ++position) ;
201 for(; position < size && !std::iswalnum(data[position]); ++position) ;
207 const auto base = [&data, &size, &position, &characters] {
208 if (data[position] == characters[0] && size > position + 1) {
209 switch (data[position + 1]) {
212 position += 2;
return 2u;
215 position += 2;
return 8u;
218 position += 2;
return 16u;
225 for(; position < size; ++position) {
226 const auto digit = [] (Char ch) {
227 if(characters[0] <= ch && ch <= characters[1])
228 return static_cast<unsigned>(ch) -
static_cast<unsigned>(characters[0]);
229 if(characters[2] <= ch && ch <= characters[4])
230 return static_cast<unsigned>(ch) -
static_cast<unsigned>(characters[2]) + 10u;
231 if(characters[3] <= ch && ch <= characters[5])
232 return static_cast<unsigned>(ch) -
static_cast<unsigned>(characters[3]) + 10u;
248 template <
typename Char, std::
size_t arrayLength>
requires (arrayLength > 1 && (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>))
249 gpu
constexpr Aeu(
const Char (&literal)[arrayLength]) noexcept :
Aeu(literal, arrayLength) {}
256 template <
typename String,
typename Char =
typename String::value_type>
requires (std::is_same_v<std::basic_string<Char>,
257 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
258 gpu
constexpr Aeu(String&& stringView) noexcept :
Aeu(stringView.data(), stringView.size()) {}
260 template <
typename String,
typename Char =
typename String::value_type>
requires (std::is_same_v<std::basic_string<Char>,
261 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
262 gpu
constexpr Aeu(
const String& stringView) noexcept :
Aeu(stringView.data(), stringView.size()) {}
264#ifdef AESI_CRYPTOPP_INTEGRATION
269 constexpr Aeu(
const CryptoPP::Integer& value):
Aeu {} {
270 const auto byteCount = value.ByteCount();
271 if(byteCount * 8 > bitness)
272 throw std::invalid_argument(
"Accessed overflow on construction object from CryptoPP::Integer");
273 for(std::size_t i = 0; i < byteCount; ++i)
274 setByte(i, value.GetByte(i));
278#ifdef AESI_GMP_INTEGRATION
283 constexpr Aeu(
const mpz_class& value) :
Aeu {} {
284 const auto bitLength = mpz_sizeinbase(value.get_mpz_t(), 2);
285 auto tBlocksNumber = 1 + (bitLength - 1) /
sizeof(block) * 8;
287 std::basic_string<block> buffer (tBlocksNumber, 0u);
288 mpz_export(buffer.data(), &tBlocksNumber, -1,
sizeof(block), -1, 0, value.get_mpz_t());
290 for (std::size_t i = 0; i < tBlocksNumber; ++i)
291 setBlock(i, buffer[i]);
313 Aeu result = *
this; makeComplement(result.blocks);
return result;
321 for(std::size_t i = 0; i < blocksNumber; ++i) {
322 if(blocks[i] < blockMax) {
325 }
else blocks[i] = 0u;
341 for(std::size_t i = 0; i < blocksNumber; ++i) {
345 blocks[i] = blockMax;
365 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>) [[nodiscard]]
366 gpu
constexpr friend auto operator+(
const Aeu& addition, Unsigned addendum)
noexcept ->
Aeu {
367 Aeu result = addition; result += addendum;
return result;
378 Aeu result = addition; result += addendum;
return result;
387 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>)
388 gpu
constexpr friend auto operator+=(
Aeu& addition, Unsigned addendum)
noexcept ->
Aeu& {
389 for(std::size_t i = 0; i < blocksNumber; ++i) {
390 const auto currentSum =
static_cast<uint64_t
>(addition.blocks[i]) +
static_cast<uint64_t
>(addendum);
391 addendum = currentSum / blockBase; addition.blocks[i] = currentSum % blockBase;
403 addLine(addition.blocks, addendum.blocks);
return addition;
417 Aeu result = subtraction; result -= subtrahend;
return result;
427 return subtraction += -subtrahend;
439 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>) [[nodiscard]]
440 gpu
constexpr friend auto operator*(
Aeu& multiplication, Unsigned factor)
noexcept ->
Aeu {
441 Aeu result = multiplication; result *= factor;
return result;
452 Aeu result = multiplication; result *= factor;
return result;
462 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned>)
463 gpu
constexpr friend auto operator*=(
Aeu& multiplication, Unsigned factor)
noexcept ->
Aeu& {
464 if constexpr (std::is_same_v<Unsigned, uint64_t>) {
466 const auto smallerLength = (factor > blockMax ? 2UL : 1UL);
469 for(std::size_t i = 0; i < longerLength; ++i) {
470 const uint64_t tBlock = multiplication.blocks[i];
471 uint64_t carryOut = 0;
473 for(std::size_t j = 0; j < smallerLength && j < buffer.size() - i; ++j) {
474 const auto product = tBlock * (factor >> blockBitLength * j & 0x00'00'00'00'ff'ff'ff'ff) + carryOut;
475 const auto block =
static_cast<uint64_t
>(buffer[i + j]) + product % blockBase;
476 carryOut = product / blockBase + block / blockBase;
477 buffer[i + j] = block % blockBase;
480 if(smallerLength + i < buffer.size())
481 buffer[smallerLength + i] += carryOut;
484 multiplication.blocks = buffer;
485 return multiplication;
487 uint64_t carryOut = 0;
488 for (std::size_t i = 0; i < blocksNumber; ++i) {
489 const auto product =
static_cast<uint64_t
>(factor) *
static_cast<uint64_t
>(multiplication.blocks[i]) + carryOut;
490 multiplication.blocks[i] = product % blockBase; carryOut = product / blockBase;
492 return multiplication;
503 constexpr auto multiplyLines = [] (
const blockLine& longerLine,
const std::size_t longerLength,
504 const blockLine& smallerLine,
const std::size_t smallerLength) {
507 for(std::size_t i = 0; i < longerLength; ++i) {
508 const uint64_t tBlock = longerLine[i];
509 uint64_t carryOut = 0;
511 for(std::size_t j = 0; j < smallerLength && j < buffer.size() - i; ++j) {
512 const auto product = tBlock *
static_cast<uint64_t
>(smallerLine[j]) + carryOut;
513 const auto block =
static_cast<uint64_t
>(buffer[i + j]) + product % blockBase;
514 carryOut = product / blockBase + block / blockBase;
515 buffer[i + j] = block % blockBase;
518 if(smallerLength < blocksNumber && smallerLength + i < buffer.size())
519 buffer[smallerLength + i] += carryOut;
526 if(
const std::size_t valueLength = factor.filledBlocksNumber(); thisLength > valueLength)
527 multiplication.blocks = multiplyLines(multiplication.blocks, thisLength, factor.blocks, valueLength);
529 multiplication.blocks = multiplyLines(factor.blocks, valueLength, multiplication.blocks, thisLength);
531 return multiplication;
546 Aeu quotient, _; divide(division, divisor, quotient, _);
return quotient;
556 gpu
constexpr friend auto operator/=(
Aeu& division,
const Aeu& divisor)
noexcept ->
Aeu& {
return division = division / divisor; }
569 Aeu _, remainder; divide(modulation, modulo, _, remainder);
return remainder;
579 return modulation = modulation % modulo;
593 for(std::size_t i = 0; i < blocksNumber; ++i)
594 result.blocks[i] = ~blocks[i];
606 Aeu result = left; result ^= right;
return result;
616 for(std::size_t i = 0; i < blocksNumber; ++i)
617 left.blocks[i] ^= right.blocks[i];
629 Aeu result = left; result &= right;
return result;
639 for(std::size_t i = 0; i < blocksNumber; ++i)
640 left.blocks[i] &= right.blocks[i];
652 Aeu result = left; result |= right;
return result;
662 for(std::size_t i = 0; i < blocksNumber; ++i)
663 left.blocks[i] |= right.blocks[i];
674 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>) [[nodiscard]]
675 gpu
constexpr friend auto operator<<(
const Aeu& value, Unsigned bitShift)
noexcept ->
Aeu {
676 Aeu result = value; result <<= bitShift;
return result;
686 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>)
687 gpu
constexpr friend auto operator<<=(
Aeu& value, Unsigned bitShift)
noexcept ->
Aeu& {
688 if(bitShift >= bitness || bitShift == 0)
return value;
690 const std::size_t quotient = bitShift / blockBitLength, remainder = bitShift % blockBitLength;
691 const block stamp = (1UL << (blockBitLength - remainder)) - 1;
693 for (
long long i = blocksNumber - 1; i >= (quotient + (remainder ? 1 : 0)); --i)
694 value.blocks[i] = (value.blocks[i - quotient] & stamp) << remainder
695 | ((value.blocks[i - quotient - (remainder ? 1 : 0)] & ~stamp) >> (blockBitLength - remainder) % blockBitLength);
697 value.blocks[quotient] = (value.blocks[0] & stamp) << remainder;
699 for (std::size_t i = 0; i < quotient; ++i)
711 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>) [[nodiscard]]
712 gpu
constexpr friend auto operator>>(
const Aeu& value, Unsigned bitShift)
noexcept ->
Aeu {
713 Aeu result = value; result >>= bitShift;
return result;
723 template <
typename Un
signed>
requires (std::is_integral_v<Unsigned> && std::is_unsigned_v<Unsigned>)
724 gpu
constexpr friend auto operator>>=(
Aeu& value, Unsigned bitShift)
noexcept ->
Aeu& {
725 if(bitShift >= bitness || bitShift == 0)
return value;
727 const std::size_t quotient = bitShift / blockBitLength, remainder = bitShift % blockBitLength;
728 const block stamp = (1UL << remainder) - 1;
730 for(std::size_t i = 0; i < blocksNumber - (quotient + (remainder ? 1 : 0)); ++i)
731 value.blocks[i] = ((value.blocks[i + quotient + (remainder ? 1 : 0)] & stamp) << (blockBitLength - remainder) % blockBitLength) | (value.blocks[i + quotient] & ~stamp) >> remainder;
733 value.blocks[blocksNumber - 1 - quotient] = (value.blocks[blocksNumber - 1] & ~stamp) >> remainder;
735 for(
long long i = blocksNumber - quotient; i < blocksNumber; ++i)
750 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned> &&
sizeof(Unsigned) < 8)
751 gpu
constexpr friend auto operator==(
const Aeu& our, Unsigned other)
noexcept ->
bool {
754 gpu
constexpr friend auto operator==(
const Aeu& our, uint64_t other)
noexcept ->
bool {
755 return our.
filledBlocksNumber() <= 2 && (
static_cast<uint64_t
>(our.blocks[1]) << blockBitLength |
static_cast<uint64_t
>(our.blocks[0])) == other;
764 gpu
constexpr friend auto operator==(
const Aeu& our,
const Aeu& other)
noexcept ->
bool =
default;
772 template <std::
size_t otherBitness>
requires (otherBitness != bitness)
774 return our.
compareTo(other) == Comparison::equal;
786 template <
typename Un
signed>
requires (std::is_unsigned_v<Unsigned> &&
sizeof(Unsigned) < 8) [[nodiscard]]
787 gpu
constexpr auto compareTo(Unsigned other)
const noexcept -> Comparison {
788 using enum Comparison;
790 if(filledBlocksNumber() > 1)
return greater;
791 const auto cmp =
static_cast<block
>(other);
809 gpu
constexpr auto compareTo(uint64_t other)
const noexcept -> Comparison {
810 using enum Comparison;
811 if(filledBlocksNumber() > 2)
return greater;
812 const auto base = (
static_cast<uint64_t
>(blocks[1]) << blockBitLength) |
static_cast<uint64_t
>(blocks[0]);
814 return greater;
else if(base < other)
return less;
else return equal;
823 template <std::
size_t otherBitness = bitness> [[nodiscard]]
825 using enum Comparison;
827 const auto lowerBlockBorder = (blocksNumber < other.totalBlocksNumber() ? blocksNumber : other.totalBlocksNumber());
828 for(
long long i = lowerBlockBorder - 1; i >= 0; --i) {
829 const block thisBlock = blocks[i], otherBlock = other.getBlock(i);
830 if(thisBlock != otherBlock)
831 return (thisBlock > otherBlock ? greater : less);
834 if constexpr (otherBitness != blocksNumber * blockBitLength) {
835 using enum Comparison;
836 if (other.totalBlocksNumber() > blocksNumber) {
837 for (
long long i = other.totalBlocksNumber() - 1; i > lowerBlockBorder - 1; --i)
838 if (other.getBlock(i) != 0)
840 }
else if (blocksNumber > other.totalBlocksNumber()) {
841 for (
long long i = blocksNumber - 1; i > lowerBlockBorder - 1; --i)
853#if (defined(__CUDACC__) || __cplusplus < 202002L || defined (PRE_CPP_20)) && !defined DOXYGEN_SKIP
857 gpu
constexpr auto operator!=(
const Aeu& value)
const noexcept ->
bool {
return !this->operator==(value); }
858 gpu
constexpr auto operator<(
const Aeu& value)
const noexcept ->
bool {
return this->compareTo(value) == Comparison::less; }
859 gpu
constexpr auto operator<=(
const Aeu& value)
const noexcept ->
bool {
return !this->operator>(value); }
860 gpu
constexpr auto operator>(
const Aeu& value)
const noexcept ->
bool {
return this->compareTo(value) == Comparison::greater; }
861 gpu
constexpr auto operator>=(
const Aeu& value)
const noexcept ->
bool {
return !this->operator<(value); }
869 gpu
constexpr auto operator<=>(
const Aeu& other)
const noexcept -> std::strong_ordering {
870 switch(this->compareTo(other)) {
871 using enum Comparison;
873 return std::strong_ordering::less;
875 return std::strong_ordering::greater;
877 return std::strong_ordering::equal;
879 return std::strong_ordering::equivalent;
889 template <
typename Un
signed>
890 gpu
constexpr auto operator<=>(
const Unsigned& other)
const noexcept -> std::strong_ordering {
891 switch(this->compareTo(other)) {
892 using enum Comparison;
894 return std::strong_ordering::less;
896 return std::strong_ordering::greater;
898 return std::strong_ordering::equal;
900 return std::strong_ordering::equivalent;
915 gpu
constexpr auto setBit(std::size_t index,
bool bit)
noexcept ->
void {
917 if(index >= bitness)
return;
919 const std::size_t blockNumber = index / blockBitLength, bitNumber = index % blockBitLength;
920 assert(blockNumber < blocksNumber && bitNumber < blockBitLength);
922 blocks[blockNumber] |= (1U << bitNumber);
924 blocks[blockNumber] &= (~(1U << bitNumber));
934 gpu
constexpr auto getBit(std::size_t index)
const noexcept ->
bool {
936 if(index >= bitness)
return false;
938 const std::size_t blockNumber = index / blockBitLength, bitNumber = index % blockBitLength;
939 assert(blockNumber < blocksNumber && bitNumber < blockBitLength);
940 return blocks[blockNumber] & (1U << bitNumber);
949 gpu
constexpr auto setByte(std::size_t index,
byte byte)
noexcept ->
void {
951 if(index > blocksNumber *
sizeof(block))
return;
953 const std::size_t blockNumber = index /
sizeof(block), byteInBlock = index %
sizeof(block), shift = byteInBlock * bitsInByte;
954 assert(blockNumber < blocksNumber && byteInBlock <
sizeof(block));
955 blocks[blockNumber] &= ~(0xffU << shift); blocks[blockNumber] |=
static_cast<block
>(byte) << shift;
965 gpu
constexpr auto getByte(std::size_t index)
const noexcept ->
byte {
967 if(index > blocksNumber *
sizeof(block))
return 0;
969 const std::size_t blockNumber = index /
sizeof(block), byteInBlock = index %
sizeof(block), shift = byteInBlock * bitsInByte;
970 assert(blockNumber < blocksNumber && byteInBlock <
sizeof(block));
971 return (blocks[blockNumber] & (0xffU << shift)) >> shift;
980 gpu
constexpr auto setBlock(std::size_t index, block block)
noexcept ->
void {
982 if(index >= blocksNumber)
return;
984 blocks[index] = block;
994 gpu
constexpr auto getBlock(std::size_t index)
const noexcept -> block {
996 if(index >= blocksNumber)
return block();
998 return blocks[index];
1006 gpu
constexpr auto byteCount() const noexcept -> std::
size_t {
1007 std::size_t lastBlock = blocksNumber - 1;
1008 for(; lastBlock > 0 && blocks[lastBlock] == 0; --lastBlock)
1011 for(int8_t byteN =
sizeof(block) - 1; byteN >= 0; --byteN) {
1012 if((blocks[lastBlock] & (0xffU << (byteN * bitsInByte))) >> (byteN * bitsInByte))
1013 return lastBlock *
sizeof(block) + byteN + 1;
1015 return lastBlock *
sizeof(block);
1023 gpu
constexpr auto bitCount() const noexcept -> std::
size_t {
1024 std::size_t lastBlock = blocksNumber - 1;
1025 for(; lastBlock > 0 && blocks[lastBlock] == 0; --lastBlock)
1028 for(int8_t byteN =
sizeof(block) - 1; byteN >= 0; --byteN) {
1029 const auto byte = (blocks[lastBlock] & (0xffU << (byteN * bitsInByte))) >> (byteN * bitsInByte);
1032 for(int8_t bitN = bitsInByte - 1; bitN >= 0; --bitN) {
1033 if((
byte & (0x1u << bitN)) >> bitN)
1034 return (lastBlock *
sizeof(block) + byteN) * bitsInByte + bitN + 1;
1036 return ((lastBlock - 1) *
sizeof(block) + byteN) * bitsInByte;
1038 return lastBlock *
sizeof(block);
1046 gpu
constexpr auto isOdd() const noexcept ->
bool {
return (0x1 & blocks[0]) == 1; }
1053 gpu
constexpr auto isEven() const noexcept ->
bool {
return (0x1 & blocks[0]) == 0; }
1060 gpu
constexpr auto isZero() const noexcept ->
bool {
return filledBlocksNumber() == 0; }
1068 for(
long long i = blocksNumber - 1; i >= 0; --i)
1069 if(blocks[i])
return i + 1;
1078 gpu
static constexpr auto getBitness() noexcept -> std::
size_t {
return bitness; }
1091 gpu
constexpr auto swap(
Aeu& other)
noexcept ->
void {
1092 Aeu t = other; other.operator=(*this); this->operator=(t);
1106 gpu
static constexpr auto divide(
const Aeu& number,
const Aeu& divisor,
Aeu& quotient,
Aeu& remainder)
noexcept ->
void {
1107 const auto ratio = number.compareTo(divisor);
1109 quotient =
Aeu {}; remainder =
Aeu {};
1111 if(ratio == Comparison::greater) {
1112 const auto bitsUsed = number.filledBlocksNumber() * blockBitLength;
1113 for(
long long i = bitsUsed - 1; i >= 0; --i) {
1115 remainder.setBit(0, number.getBit(i));
1117 if(remainder >= divisor) {
1118 remainder -= divisor;
1119 quotient.setBit(i,
true);
1122 }
else if(ratio == Comparison::less)
1123 remainder = number;
else quotient = 1u;
1133 gpu
static constexpr auto divide(
const Aeu& number,
const Aeu& divisor)
noexcept -> pair<Aeu, Aeu> {
1134 pair<Aeu, Aeu> results; divide(number, divisor, results.first, results.second);
return results;
1146 gpu
static constexpr auto gcd(
const Aeu& first,
const Aeu& second,
Aeu& bezoutX,
Aeu& bezoutY)
noexcept ->
Aeu {
1147 Aeu gcd, quotient, remainder;
1149 const auto ratio = first.
compareTo(second);
1150 if(ratio == Comparison::greater) {
1152 divide(first, second, quotient, remainder);
1155 divide(second, first, quotient, remainder);
1158 bezoutX = 0u; bezoutY = 1u;
1159 for(
Aeu tX = 1u, tY = 0u; remainder != 0u; ) {
1160 Aeu tGcd = gcd; gcd = remainder;
1162 Aeu t = bezoutX; bezoutX = tX - quotient * bezoutX; tX = t;
1163 t = bezoutY; bezoutY = tY - quotient * bezoutY; tY = t;
1165 divide(tGcd, gcd, quotient, remainder);
1168 if(ratio != Comparison::greater)
1169 bezoutX.swap(bezoutY);
1181 gpu
static constexpr auto gcd(
const Aeu& first,
const Aeu& second)
noexcept ->
Aeu {
1182 Aeu gcd, quotient, remainder;
1184 const auto ratio = first.
compareTo(second);
1185 if(ratio == Comparison::greater) {
1187 divide(first, second, quotient, remainder);
1190 divide(second, first, quotient, remainder);
1193 for(
Aeu tX = 1u, tY = 0u; remainder != 0u; ) {
1194 Aeu tGcd = gcd; gcd = remainder;
1195 divide(tGcd, gcd, quotient, remainder);
1208 gpu
static constexpr auto lcm(
const Aeu& first,
const Aeu& second)
noexcept ->
Aeu {
return first / gcd(first, second) * second; }
1219 template <std::
size_t powerBitness = bitness> [[nodiscard]]
1227 auto [_, b] = divide(base, modulo);
1229 for(
unsigned iteration = 0; power.filledBlocksNumber() * blockBitLength != iteration; iteration++) {
1230 if(power.getBit(iteration)) {
1231 const auto [quotient, remainder] = divide(output * b, modulo);
1235 const auto [quotient, remainder] = divide(b * b, modulo);
1243 gpu
static constexpr auto powm(
const Aeu& base,
const Aeu& power,
const Aeu& mod)
noexcept ->
Aeu {
1245 auto [_, b] = divide(base, mod);
1247 for(std::size_t iteration = 0; power.filledBlocksNumber() * blockBitLength != iteration; iteration++) {
1248 if(power.getBit(iteration)) {
1249 const auto [quotient, remainder] = divide(output * b, mod);
1253 const auto [quotient, remainder] = divide(b * b, mod);
1267 gpu
static constexpr auto power2(std::size_t power)
noexcept ->
Aeu {
Aeu result {}; result.
setBit(power,
true);
return result; }
1276 Aeu x, y = power2((bitCount() + 1) / 2);
1280 y = (x + *
this / x) >> 1u;
1299 template <
byte base,
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t> && (base == 2 || base == 8 || base == 10 || base == 16))
1300 gpu
constexpr auto getString(Char*
const buffer, std::size_t bufferSize,
bool showBase =
false,
bool hexUppercase =
false)
const noexcept -> std::size_t {
1301 if(bufferSize < 2)
return 0;
1303 std::size_t position = 0;
1305 if (showBase && bufferSize > 3) {
1306 if constexpr (base == 2) {
1307 if constexpr (std::is_same_v<Char, char>) {
1308 buffer[0] =
'0'; buffer[1] =
'b';
1310 buffer[0] = L
'0'; buffer[1] = L
'b';
1313 }
else if constexpr (base == 8) {
1314 if constexpr (std::is_same_v<Char, char>) {
1315 buffer[0] =
'0'; buffer[1] =
'o';
1317 buffer[0] = L
'0'; buffer[1] = L
'o';
1320 }
else if constexpr (base == 16) {
1321 if constexpr (std::is_same_v<Char, char>) {
1322 buffer[0] =
'0'; buffer[1] =
'x';
1324 buffer[0] = L
'0'; buffer[1] = L
'x';
1331 buffer[position++] = [] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; }}();
1335 if constexpr (base == 16) {
1336 long long iter = blocks.size() - 1;
1337 for (; blocks[iter] == 0 && iter >= 0; --iter)
1340 if constexpr (std::is_same_v<Char, char>) {
1341 position += snprintf(buffer + position, bufferSize - position, (hexUppercase ?
"%X" :
"%x"), blocks[iter--]);
1342 for (; iter >= 0; --iter)
1343 position += snprintf(buffer + position, bufferSize - position, (hexUppercase ?
"%08X" :
"%08x"), blocks[iter]);
1345 position += swprintf(buffer + position, bufferSize - position, (hexUppercase ? L
"%X" : L
"%x"), blocks[iter--]);
1346 for (; iter >= 0; --iter)
1347 position += swprintf(buffer + position, bufferSize - position, (hexUppercase ? L
"%08X" : L
"%08x"), blocks[iter]);
1350 const auto startPosition = position;
1353 while (!copy.
isZero() && position < bufferSize) {
1354 auto [quotient, remainder] = divide(copy, base);
1355 if constexpr (std::is_same_v<Char, char>) {
1356 buffer[position++] =
'0' + remainder.template integralCast<byte>();
1358 buffer[position++] = L
'0' + remainder.template integralCast<byte>();
1362 const auto digitsTotal = position - startPosition;
1363 for (std::size_t i = 0; i * 2 < digitsTotal; ++i) {
1364 Char t = buffer[startPosition + i];
1365 buffer[startPosition + i] = buffer[startPosition + digitsTotal - 1 - i];
1366 buffer[startPosition + digitsTotal - 1 - i] = t;
1369 buffer[position++] = Char {};
1384 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1385 friend constexpr auto operator<<(std::basic_ostream<Char>& os,
const Aeu& number) -> std::basic_ostream<Char>& {
1386 auto flags = os.flags();
1388 const auto base = [] (
long baseField, std::basic_ostream<Char>& ss,
bool showbase) {
1389 auto tBase = (baseField == std::ios::hex ? 16u : (baseField == std::ios::oct ? 8u : 10u));
1390 if(showbase && tBase != 10)
1392 if constexpr (std::is_same_v<Char, char>) {
1393 return tBase == 8 ?
"0o" :
"0x";
1395 return tBase == 8 ? L
"0o" : L
"0x";
1397 } () << std::noshowbase ;
1399 } (flags & std::ios::basefield, os, flags & std::ios::showbase);
1405 long long iter = number.blocks.size() - 1;
1406 for(; number.blocks[iter] == 0 && iter >= 0; --iter)
1409 os << number.blocks[iter--];
1410 for (; iter >= 0; --iter) {
1411 os.fill([] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; } } ());
1412 os.width(8); os << std::right << number.blocks[iter];
1417 constexpr auto bufferSize =
static_cast<std::size_t
>(
static_cast<double>(bitness) / 2.95);
1418 Char buffer [bufferSize] {}; std::size_t filled = 0;
1421 while(!copy.
isZero() && filled < bufferSize) {
1422 const auto [quotient, remainder] = divide(copy, base);
1423 buffer[filled++] = [] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; } } () + remainder.template integralCast<byte>();
1427 for(; filled > 0; --filled)
1428 os << buffer[filled - 1];
1443 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1444 constexpr auto readBinary(std::basic_istream<Char>& is,
bool bigEndian =
true) ->
void {
1447 for(
auto it = blocks.rbegin(); it != blocks.rend(); ++it)
1448 if(!is.read(
reinterpret_cast<char*
>(&*it),
sizeof(block)))
break;
1450 for(
auto& tBlock: blocks)
1451 if(!is.read(
reinterpret_cast<char*
>(&tBlock),
sizeof(block)))
break;
1462 template <
typename Char>
requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1463 constexpr auto writeBinary(std::basic_ostream<Char>& os,
bool bigEndian =
true)
const noexcept ->
void {
1465 for(
auto it = blocks.rbegin(); it != blocks.rend(); ++it)
1466 if(!os.write(
reinterpret_cast<const char*
>(&*it),
sizeof(block)))
break;
1468 for(
auto& block: blocks)
1469 if(!os.write(
reinterpret_cast<const char*
>(&block),
sizeof(block)))
break;
1481 template <
typename Integral>
requires (std::is_integral_v<Integral>) [[nodiscard]]
1483 const uint64_t value = (
static_cast<uint64_t
>(blocks[1]) << blockBitLength) |
static_cast<uint64_t
>(blocks[0]);
1484 return static_cast<Integral
>(value);
1495 template <std::
size_t newBitness>
requires (newBitness != bitness) [[nodiscard]]
1500 for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
1501 result.
setBlock(blockIdx, getBlock(blockIdx));
1508#if defined __CUDACC__
1516 __device__
constexpr auto tryAtomicSet(
const Aeu& value)
noexcept ->
void {
1517 for(std::size_t i = 0; i < blocksNumber; ++i)
1518 atomicExch(&blocks[i], value.blocks[i]);
1527 __device__
constexpr auto tryAtomicExchange(
const Aeu& value)
noexcept ->
void {
1528 for(std::size_t i = 0; i < blocksNumber; ++i)
1529 atomicExch(&value.blocks[i], atomicExch(&blocks[i], value.blocks[i]));
1599template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1608template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1617template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1626template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1635template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1644template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1653template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1662template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
Long precision unsigned integer.
Definition Aeu.h:83
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:1146
gpu constexpr auto operator<=>(const Aeu &other) const noexcept -> std::strong_ordering
Three-way comparison operator.
Definition Aeu.h:869
gpu constexpr friend auto operator|=(Aeu &left, const Aeu &right) noexcept -> Aeu &
Assignment bitwise OR operator.
Definition Aeu.h:661
gpu constexpr auto bitCount() const noexcept -> std::size_t
Get amount of non-empty bits in number right to left.
Definition Aeu.h:1023
gpu constexpr friend auto operator&(const Aeu &left, const Aeu &right) noexcept -> Aeu
Bitwise AND operator.
Definition Aeu.h:628
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:787
gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t
Get number of non-empty blocks inside object starting from the right.
Definition Aeu.h:1067
gpu constexpr auto operator+() const noexcept -> Aeu
Unary plus operator.
Definition Aeu.h:305
gpu constexpr auto getString(Char *const buffer, std::size_t bufferSize, bool showBase=false, bool hexUppercase=false) const noexcept -> std::size_t
Character buffer output operator.
Definition Aeu.h:1300
gpu constexpr friend auto operator/(const Aeu &division, const Aeu &divisor) noexcept -> Aeu
Division operator.
Definition Aeu.h:545
static gpu constexpr auto power2(std::size_t power) noexcept -> Aeu
Fast exponentiation for powers of 2.
Definition Aeu.h:1267
static gpu constexpr auto gcd(const Aeu &first, const Aeu &second) noexcept -> Aeu
Greatest common divisor.
Definition Aeu.h:1181
gpu constexpr auto isEven() const noexcept -> bool
Check whether number is even.
Definition Aeu.h:1053
gpu constexpr auto operator~() const noexcept -> Aeu
Bitwise complement operator.
Definition Aeu.h:591
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:949
gpu constexpr friend auto operator+(const Aeu &addition, const Aeu &addendum) noexcept -> Aeu
Addition operator.
Definition Aeu.h:377
gpu constexpr Aeu(String &&stringView) noexcept
String or string-view based constructor.
Definition Aeu.h:258
gpu constexpr friend auto operator%(const Aeu &modulation, const Aeu &modulo) noexcept -> Aeu
Modulo operator.
Definition Aeu.h:568
gpu constexpr auto byteCount() const noexcept -> std::size_t
Get amount of non-empty bytes in number right to left.
Definition Aeu.h:1006
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:980
gpu constexpr friend auto operator&=(Aeu &left, const Aeu &right) noexcept -> Aeu &
Assignment bitwise AND operator.
Definition Aeu.h:638
gpu constexpr auto getByte(std::size_t index) const noexcept -> byte
Get byte in number by index starting from the right.
Definition Aeu.h:965
gpu constexpr Aeu(const Char(&literal)[arrayLength]) noexcept
C-style string literal constructor.
Definition Aeu.h:249
gpu constexpr auto operator--(int) &noexcept -> Aeu
Postfix decrement.
Definition Aeu.h:354
static gpu constexpr auto powm(const Aeu &base, const Aeu< powerBitness > &power, const Aeu &modulo) noexcept -> Aeu
Exponentiation by modulo.
Definition Aeu.h:1220
gpu constexpr auto integralCast() const noexcept -> Integral
Integral type cast operator for built-in types.
Definition Aeu.h:1482
gpu constexpr friend auto operator-=(Aeu &subtraction, const Aeu &subtrahend) noexcept -> Aeu &
Assignment subtraction operator.
Definition Aeu.h:426
gpu constexpr auto isOdd() const noexcept -> bool
Check whether number is odd.
Definition Aeu.h:1046
gpu constexpr friend auto operator^=(Aeu &left, const Aeu &right) noexcept -> Aeu &
Assignment bitwise XOR operator.
Definition Aeu.h:615
constexpr auto writeBinary(std::basic_ostream< Char > &os, bool bigEndian=true) const noexcept -> void
STD stream binary writing operator.
Definition Aeu.h:1463
static gpu constexpr auto divide(const Aeu &number, const Aeu &divisor) noexcept -> pair< Aeu, Aeu >
Integer division. Returns results by value.
Definition Aeu.h:1133
gpu constexpr auto swap(Aeu &other) noexcept -> void
Make swap between two objects.
Definition Aeu.h:1091
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:1106
gpu constexpr auto operator++(int) &noexcept -> Aeu
Postfix increment.
Definition Aeu.h:334
static gpu constexpr auto getBitness() noexcept -> std::size_t
Get number's precision.
Definition Aeu.h:1078
gpu constexpr friend auto operator|(const Aeu &left, const Aeu &right) noexcept -> Aeu
Bitwise OR operator.
Definition Aeu.h:651
gpu constexpr friend auto operator^(const Aeu &left, const Aeu &right) noexcept -> Aeu
Bitwise XOR operator.
Definition Aeu.h:605
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:915
gpu constexpr auto precisionCast() const noexcept -> Aeu< newBitness >
Precision cast operator.
Definition Aeu.h:1496
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:1085
gpu constexpr auto isZero() const noexcept -> bool
Check whether number is zero.
Definition Aeu.h:1060
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:890
gpu constexpr friend auto operator%=(Aeu &modulation, const Aeu &modulo) noexcept -> Aeu &
Assignment modulo operator.
Definition Aeu.h:578
gpu constexpr friend auto operator/=(Aeu &division, const Aeu &divisor) noexcept -> Aeu &
Assignment division operator.
Definition Aeu.h:556
gpu constexpr auto operator--() noexcept -> Aeu &
Prefix decrement.
Definition Aeu.h:340
constexpr auto readBinary(std::basic_istream< Char > &is, bool bigEndian=true) -> void
STD stream binary reading operator.
Definition Aeu.h:1444
gpu constexpr Aeu(const Char *data, std::size_t size) noexcept
Pointer-based character constructor.
Definition Aeu.h:186
gpu constexpr auto compareTo(uint64_t other) const noexcept -> Comparison
Internal comparison operator for type uint64_t.
Definition Aeu.h:809
gpu constexpr friend auto operator*=(Aeu &multiplication, const Aeu &factor) noexcept -> Aeu &
Assignment multiplication operator.
Definition Aeu.h:502
gpu constexpr friend auto operator+=(Aeu &addition, const Aeu &addendum) noexcept -> Aeu &
Assignment addition operator.
Definition Aeu.h:402
static gpu constexpr auto lcm(const Aeu &first, const Aeu &second) noexcept -> Aeu
Least common multiplier.
Definition Aeu.h:1208
gpu constexpr auto getBit(std::size_t index) const noexcept -> bool
Get bit in number by index staring from the right.
Definition Aeu.h:934
gpu constexpr friend auto operator-(const Aeu &subtraction, const Aeu &subtrahend) noexcept -> Aeu
Subtraction operator.
Definition Aeu.h:416
gpu constexpr friend auto operator==(const Aeu &our, const Aeu &other) noexcept -> bool=default
Equality check operator for numbers of the same precision.
gpu constexpr auto squareRoot() const noexcept -> Aeu
Get square root.
Definition Aeu.h:1275
gpu constexpr auto getBlock(std::size_t index) const noexcept -> block
Get block in number by index starting from the right.
Definition Aeu.h:994
gpu constexpr friend auto operator*(const Aeu &multiplication, const Aeu &factor) noexcept -> Aeu
Multiplication operator.
Definition Aeu.h:451
gpu constexpr auto operator-() const noexcept -> Aeu
Unary minus operator.
Definition Aeu.h:312
gpu constexpr auto operator++() noexcept -> Aeu &
Prefix increment.
Definition Aeu.h:320
gpu constexpr auto compareTo(const Aeu< otherBitness > &other) const noexcept -> Comparison
Internal comparison operator.
Definition Aeu.h:824
gpu constexpr Aeu() noexcept=default
Default constructor.