Aesi Multiprecision
C++ class library of long integer arithmetic for GPU parallelization
Loading...
Searching...
No Matches
Aeu.h
Go to the documentation of this file.
1
31#ifndef AEU_MULTIPRECISION
32#define AEU_MULTIPRECISION
33
35#include <cstdint>
36#include <cctype>
37#include <cwctype>
38#include <iostream>
39#include <cassert>
40
41#ifdef __CUDACC__
42#define gpu __host__ __device__
43 #include <cuda/std/utility>
44 #include <cuda/std/array>
45#else
46#define gpu
47 #include <utility>
48 #include <array>
49 #include <vector>
50#endif
52
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
55#endif
56
57
58#ifdef AESI_GMP_INTEGRATION
59#include <gmpxx.h>
60#endif
61
62namespace {
63 using byte = uint8_t;
64 using block = uint32_t;
65
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;
70
75 enum class Comparison { equal = 0, less = 1, greater = 2, equivalent = 3 };
76}
77
83template <std::size_t bitness = 512> requires (bitness % blockBitLength == 0)
84class Aeu final {
85 static_assert(bitness > sizeof(uint64_t), "Use built-in types for numbers 64-bit or less.");
86
87 static constexpr std::size_t blocksNumber = bitness / blockBitLength;
88
89#ifdef __CUDACC__
90 template <typename T1, typename T2>
91 using pair = cuda::std::pair<T1, T2>;
92 using blockLine = cuda::std::array<block, blocksNumber>;
93#else
94 template<typename T1, typename T2>
95 using pair = std::pair<T1, T2>;
96 using blockLine = std::array<block, blocksNumber>;
97#endif
98
99 /* -------------------------- @name Class members. ----------------------- */
103 blockLine blocks;
104 /* ----------------------------------------------------------------------- */
105
106 /* ------------------------ @name Helper functions. ---------------------- */
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);
118 }
119 return carryOut;
120 }
121
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);
132 }
133 return carryOut;
134 }
135 /* ----------------------------------------------------------------------- */
136
137public:
138 /* --------------------- @name Different constructors. ------------------- */
142 constexpr Aeu() noexcept = default;
143
147 constexpr ~Aeu() noexcept = default;
148
152 constexpr Aeu(const Aeu& copy) noexcept = default;
153
158 constexpr Aeu& operator=(const Aeu& other) = default;
159
166 template <typename Integral> requires (std::is_unsigned_v<Integral>)
167 gpu constexpr Aeu(Integral value) noexcept {
168 if(value != 0) {
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);
172 tValue /= blockBase;
173 }
174 } else
175 blocks = {};
176 }
177
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;
187
188 std::size_t position = 0;
189
190 if constexpr (std::is_same_v<Char, char>) {
191 for(; position < size && !std::isalnum(data[position]); ++position) ;
192 } else {
193 for(; position < size && !std::iswalnum(static_cast<wint_t>(data[position])); ++position) ;
194 }
195
196 if(position == size)
197 return;
198
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;
208 default:
209 return 10u;
210 }
211 } return 10u;
212 } ();
213
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;
222 return 99u;
223 } (data[position]);
224
225 if(digit < base) {
226 *this *= base;
227 *this += digit;
228 }
229 }
230 }
231
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) {}
239
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()) {}
248
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()) {}
252
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;
261
262 std::vector<block> buffer (tBlocksNumber, 0u);
263 mpz_export(buffer.data(), &tBlocksNumber, -1, sizeof(block), -1, 0, value.get_mpz_t());
264
265 for (std::size_t i = 0; i < tBlocksNumber; ++i)
266 setBlock(i, buffer[i]);
267 }
268#endif
269 /* ----------------------------------------------------------------------- */
270
271
272 /* --------------------- @name Arithmetic operators. --------------------- */
273 /* ------------------------- @name Unary operators. -------------------------- */
279 [[nodiscard]]
280 gpu constexpr auto operator+() const noexcept -> Aeu { return *this; }
281
286 [[nodiscard]]
287 gpu constexpr auto operator-() const noexcept -> Aeu {
288 Aeu result = *this; makeComplement(result.blocks); return result;
289 }
290
295 gpu constexpr auto operator++() noexcept -> Aeu& {
296 for(std::size_t i = 0; i < blocksNumber; ++i) {
297 if(blocks[i] < blockMax) {
298 ++blocks[i];
299 break;
300 } else blocks[i] = 0u;
301 }
302 return *this;
303 }
304
309 gpu constexpr auto operator++(int) & noexcept -> Aeu { Aeu old = *this; operator++(); return old; }
310
315 gpu constexpr auto operator--() noexcept -> Aeu& {
316 for(std::size_t i = 0; i < blocksNumber; ++i) {
317 if(blocks[i] > 0u) {
318 --blocks[i]; break;
319 }
320 blocks[i] = blockMax;
321 }
322 return *this;
323 }
324
329 gpu constexpr auto operator--(int) & noexcept -> Aeu { Aeu old = *this; operator--(); return old; }
330 /* --------------------------------------------------------------------------- */
331
332
333 /* ------------------------ @name Addition operators. ------------------------ */
340 template <typename Unsigned> 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;
343 }
344
351 [[nodiscard]]
352 gpu constexpr friend auto operator+(const Aeu& addition, const Aeu& addendum) noexcept -> Aeu {
353 Aeu result = addition; result += addendum; return result;
354 }
355
362 template <typename Unsigned> 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);
367 }
368 return addition;
369 }
370
377 gpu constexpr friend auto operator+=(Aeu& addition, const Aeu& addendum) noexcept -> Aeu& {
378 addLine(addition.blocks, addendum.blocks); return addition;
379 }
380 /* --------------------------------------------------------------------------- */
381
382
383 /* ----------------------- @name Subtraction operators. ---------------------- */
390 [[nodiscard]]
391 gpu constexpr friend auto operator-(const Aeu& subtraction, const Aeu& subtrahend) noexcept -> Aeu {
392 Aeu result = subtraction; result -= subtrahend; return result;
393 }
394
401 gpu constexpr friend auto operator-=(Aeu& subtraction, const Aeu& subtrahend) noexcept -> Aeu& {
402 return subtraction += -subtrahend;
403 }
404 /* --------------------------------------------------------------------------- */
405
406
407 /* --------------------- @name Multiplication operators. --------------------- */
414 template <typename Unsigned> 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;
417 }
418
425 [[nodiscard]]
426 gpu constexpr friend auto operator*(const Aeu& multiplication, const Aeu& factor) noexcept -> Aeu {
427 Aeu result = multiplication; result *= factor; return result;
428 }
429
437 template <typename Unsigned> 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>) {
440 const auto longerLength = multiplication.filledBlocksNumber();
441 const auto smallerLength = (factor > blockMax ? 2UL : 1UL);
442 blockLine buffer {};
443
444 for(std::size_t i = 0; i < longerLength; ++i) {
445 const uint64_t tBlock = multiplication.blocks[i];
446 uint64_t carryOut = 0;
447
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);
453 }
454
455 if(smallerLength + i < buffer.size())
456 buffer[smallerLength + i] += static_cast<block>(carryOut);
457 }
458
459 multiplication.blocks = buffer;
460 return multiplication;
461 } else {
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;
466 }
467 return multiplication;
468 }
469 }
470
477 gpu constexpr friend auto operator*=(Aeu& multiplication, const Aeu& factor) noexcept -> Aeu& {
478 constexpr auto multiplyLines = [] (const blockLine& longerLine, const std::size_t longerLength,
479 const blockLine& smallerLine, const std::size_t smallerLength) {
480 blockLine buffer {};
481
482 for(std::size_t i = 0; i < longerLength; ++i) {
483 const uint64_t tBlock = longerLine[i];
484 uint64_t carryOut = 0;
485
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);
491 }
492
493 if(smallerLength < blocksNumber && smallerLength + i < buffer.size())
494 buffer[smallerLength + i] += static_cast<block>(carryOut);
495 }
496
497 return buffer;
498 };
499
500 const std::size_t thisLength = multiplication.filledBlocksNumber();
501 if(const std::size_t valueLength = factor.filledBlocksNumber(); thisLength > valueLength)
502 multiplication.blocks = multiplyLines(multiplication.blocks, thisLength, factor.blocks, valueLength);
503 else
504 multiplication.blocks = multiplyLines(factor.blocks, valueLength, multiplication.blocks, thisLength);
505
506 return multiplication;
507 }
508 /* --------------------------------------------------------------------------- */
509
510
511 /* ------------------------ @name Division operators. ------------------------ */
519 [[nodiscard]]
520 gpu constexpr friend auto operator/(const Aeu& division, const Aeu& divisor) noexcept -> Aeu {
521 Aeu quotient, _; divide(division, divisor, quotient, _); return quotient;
522 }
523
531 gpu constexpr friend auto operator/=(Aeu& division, const Aeu& divisor) noexcept -> Aeu& { return division = division / divisor; }
532 /* --------------------------------------------------------------------------- */
533
534
535 /* ------------------------- @name Modulo operators. ------------------------- */
542 [[nodiscard]]
543 gpu constexpr friend auto operator%(const Aeu& modulation, const Aeu& modulo) noexcept -> Aeu {
544 Aeu _, remainder; divide(modulation, modulo, _, remainder); return remainder;
545 }
546
553 gpu constexpr friend auto operator%=(Aeu& modulation, const Aeu& modulo) noexcept -> Aeu& {
554 return modulation = modulation % modulo;
555 }
556 /* --------------------------------------------------------------------------- */
557 /* ----------------------------------------------------------------------- */
558
559
560 /* ----------------------- @name Bitwise operators. ---------------------- */
565 [[nodiscard]]
566 gpu constexpr auto operator~() const noexcept -> Aeu {
567 Aeu result;
568 for(std::size_t i = 0; i < blocksNumber; ++i)
569 result.blocks[i] = ~blocks[i];
570 return result;
571 }
572
579 [[nodiscard]]
580 gpu constexpr friend auto operator^(const Aeu& left, const Aeu& right) noexcept -> Aeu {
581 Aeu result = left; result ^= right; return result;
582 }
583
590 gpu constexpr friend auto operator^=(Aeu& left, const Aeu& right) noexcept -> Aeu& {
591 for(std::size_t i = 0; i < blocksNumber; ++i)
592 left.blocks[i] ^= right.blocks[i];
593 return left;
594 }
595
602 [[nodiscard]]
603 gpu constexpr friend auto operator&(const Aeu& left, const Aeu& right) noexcept -> Aeu {
604 Aeu result = left; result &= right; return result;
605 }
606
613 gpu constexpr friend auto operator&=(Aeu& left, const Aeu& right) noexcept -> Aeu& {
614 for(std::size_t i = 0; i < blocksNumber; ++i)
615 left.blocks[i] &= right.blocks[i];
616 return left;
617 }
618
625 [[nodiscard]]
626 gpu constexpr friend auto operator|(const Aeu& left, const Aeu& right) noexcept -> Aeu {
627 Aeu result = left; result |= right; return result;
628 }
629
636 gpu constexpr friend auto operator|=(Aeu& left, const Aeu& right) noexcept -> Aeu& {
637 for(std::size_t i = 0; i < blocksNumber; ++i)
638 left.blocks[i] |= right.blocks[i];
639 return left;
640 }
641
649 template <typename Unsigned> 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;
652 }
653
661 template <typename Unsigned> 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;
664
665 const std::size_t quotient = bitShift / blockBitLength, remainder = bitShift % blockBitLength;
666 const block stamp = static_cast<block>((1ULL << (blockBitLength - remainder)) - 1);
667
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);
672
673 value.blocks[quotient] = (value.blocks[0] & stamp) << remainder;
674
675 for (std::size_t i = 0; i < quotient; ++i)
676 value.blocks[i] = 0;
677 return value;
678 }
679
687 template <typename Unsigned> 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;
690 }
691
699 template <typename Unsigned> 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;
702
703 const std::size_t quotient = bitShift / blockBitLength, remainder = bitShift % blockBitLength;
704 const block stamp = static_cast<block>((1ULL << remainder) - 1);
705
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;
708
709 value.blocks[blocksNumber - 1 - quotient] = (value.blocks[blocksNumber - 1] & ~stamp) >> remainder;
710
711 for(std::size_t i = blocksNumber - quotient; i < blocksNumber; ++i)
712 value.blocks[i] = 0;
713 return value;
714 }
715 /* ----------------------------------------------------------------------- */
716
717
718 /* --------------------- @name Comparison operators. --------------------- */
719 /* ------------------------ @name Equality operators. ------------------------ */
726 template <typename Unsigned> requires (std::is_unsigned_v<Unsigned> && sizeof(Unsigned) < 8)
727 gpu constexpr friend auto operator==(const Aeu& our, Unsigned other) noexcept -> bool {
728 return our.filledBlocksNumber() <= 1 && static_cast<block>(other) == our.blocks[0];
729 }
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;
732 }
733
740 template <std::size_t otherBitness>
741 gpu constexpr friend auto operator==(const Aeu& our, const Aeu<otherBitness>& other) noexcept -> bool {
742 return our.compareTo(other) == Comparison::equal;
743 }
744
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));
755 }
756#endif
757 /* --------------------------------------------------------------------------- */
758
759
760 /* ----------------------- @name Comparison operators. ----------------------- */
767 template <typename Unsigned> requires (std::is_unsigned_v<Unsigned> && sizeof(Unsigned) < 8) [[nodiscard]]
768 gpu constexpr auto compareTo(Unsigned other) const noexcept -> Comparison {
769 using enum Comparison;
770
771 if(filledBlocksNumber() > 1) return greater;
772 const auto cmp = static_cast<block>(other);
773
774 if(blocks[0] > cmp)
775 return greater;
776
777 if(blocks[0] < cmp)
778 return less;
779
780 return equal;
781 }
782
789 [[nodiscard]]
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]);
794 if(base > other)
795 return greater; else if(base < other) return less; else return equal;
796 }
797
804 template <std::size_t otherBitness = bitness> /*requires (otherBitness != bitness)*/ [[nodiscard]]
805 gpu constexpr auto compareTo(const Aeu<otherBitness>& other) const noexcept -> Comparison {
806 using enum Comparison;
807
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);
813 }
814
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)
820 return less;
821 } else if (blocksNumber > other.totalBlocksNumber()) {
822 for (std::size_t i = blocksNumber; i-- > lowerBlockBorder;)
823 if (blocks[i] != 0)
824 return greater;
825 }
826 }
827
828 return equal;
829 }
830 /* --------------------------------------------------------------------------- */
831
832
833 /* ------------------------ @name Spaceship operators. ----------------------- */
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); }
843#else
850 gpu constexpr auto operator<=>(const Aeu& other) const noexcept -> std::strong_ordering {
851 switch(this->compareTo(other)) {
852 using enum Comparison;
853 case less:
854 return std::strong_ordering::less;
855 case greater:
856 return std::strong_ordering::greater;
857 case equal:
858 return std::strong_ordering::equal;
859 default:
860 return std::strong_ordering::equivalent;
861 }
862 }
863
870 template <typename Unsigned>
871 gpu constexpr auto operator<=>(const Unsigned& other) const noexcept -> std::strong_ordering {
872 switch(this->compareTo(other)) {
873 using enum Comparison;
874 case less:
875 return std::strong_ordering::less;
876 case greater:
877 return std::strong_ordering::greater;
878 case equal:
879 return std::strong_ordering::equal;
880 default:
881 return std::strong_ordering::equivalent;
882 }
883 }
884#endif
885 /* --------------------------------------------------------------------------- */
886 /* ----------------------------------------------------------------------- */
887
888
889 /* ---------------------- @name Supporting methods. ---------------------- */
896 gpu constexpr auto setBit(std::size_t index, bool bit) noexcept -> void {
897#ifndef AESI_UNSAFE
898 if(index >= bitness) return;
899#endif
900 const std::size_t blockNumber = index / blockBitLength, bitNumber = index % blockBitLength;
901 assert(blockNumber < blocksNumber && bitNumber < blockBitLength);
902 if(bit)
903 blocks[blockNumber] |= (1U << bitNumber);
904 else
905 blocks[blockNumber] &= (~(1U << bitNumber));
906 }
907
914 [[nodiscard]]
915 gpu constexpr auto getBit(std::size_t index) const noexcept -> bool {
916#ifndef AESI_UNSAFE
917 if(index >= bitness) return false;
918#endif
919 const std::size_t blockNumber = index / blockBitLength, bitNumber = index % blockBitLength;
920 assert(blockNumber < blocksNumber && bitNumber < blockBitLength);
921 return blocks[blockNumber] & (1U << bitNumber);
922 }
923
930 gpu constexpr auto setByte(std::size_t index, byte byte) noexcept -> void {
931#ifndef AESI_UNSAFE
932 if(index > blocksNumber * sizeof(block)) return;
933#endif
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;
937 }
938
945 [[nodiscard]]
946 gpu constexpr auto getByte(std::size_t index) const noexcept -> byte {
947#ifndef AESI_UNSAFE
948 if(index > blocksNumber * sizeof(block)) return 0;
949#endif
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);
953 }
954
961 gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void {
962#ifndef AESI_UNSAFE
963 if(index >= blocksNumber) return;
964#endif
965 blocks[index] = block;
966 }
967
974 [[nodiscard]]
975 gpu constexpr auto getBlock(std::size_t index) const noexcept -> block {
976#ifndef AESI_UNSAFE
977 if(index >= blocksNumber) return block();
978#endif
979 return blocks[index];
980 }
981
986 [[nodiscard]]
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)
990 ;
991
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;
995 }
996 return lastBlock * sizeof(block);
997 }
998
1003 [[nodiscard]]
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)
1007 ;
1008
1009 for(std::size_t byteN = sizeof(block); byteN-- > 0;) {
1010 const auto byte = (blocks[lastBlock] & (0xffU << (byteN * bitsInByte))) >> (byteN * bitsInByte);
1011 if(!byte) continue;
1012
1013 for(std::size_t bitN = bitsInByte; bitN-- > 0;) {
1014 if((byte & (0x1u << bitN)) >> bitN)
1015 return (lastBlock * sizeof(block) + byteN) * bitsInByte + bitN + 1;
1016 }
1017 return ((lastBlock - 1) * sizeof(block) + byteN) * bitsInByte;
1018 }
1019 return lastBlock * sizeof(block);
1020 }
1021
1026 [[nodiscard]]
1027 gpu constexpr auto isOdd() const noexcept -> bool { return (0x1 & blocks[0]) == 1; }
1028
1033 [[nodiscard]]
1034 gpu constexpr auto isEven() const noexcept -> bool { return (0x1 & blocks[0]) == 0; }
1035
1040 [[nodiscard]]
1041 gpu constexpr auto isZero() const noexcept -> bool { return filledBlocksNumber() == 0; }
1042
1047 [[nodiscard]]
1048 gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t {
1049 for(std::size_t i = blocksNumber; i-- > 0;)
1050 if(blocks[i]) return i + 1;
1051 return 0;
1052 }
1053
1058 [[nodiscard]]
1059 gpu static constexpr auto getBitness() noexcept -> std::size_t { return bitness; }
1060
1065 [[nodiscard]]
1066 gpu static constexpr auto totalBlocksNumber() noexcept -> std::size_t { return blocksNumber; }
1067
1072 gpu constexpr auto swap(Aeu& other) noexcept -> void {
1073 Aeu t = other; other.operator=(*this); this->operator=(t);
1074 }
1075 /* ----------------------------------------------------------------------- */
1076
1077
1078 /* -------------- @name Public arithmetic and number theory. ------------- */
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);
1089
1090 quotient = Aeu {}; remainder = Aeu {};
1091
1092 if(ratio == Comparison::greater) {
1093 const auto bitsUsed = number.filledBlocksNumber() * blockBitLength;
1094 for(std::size_t i = bitsUsed; i-- > 0;) {
1095 remainder <<= 1u;
1096 remainder.setBit(0, number.getBit(i));
1097
1098 if(remainder >= divisor) {
1099 remainder -= divisor;
1100 quotient.setBit(i, true);
1101 }
1102 }
1103 } else if(ratio == Comparison::less)
1104 remainder = number; else quotient = 1u;
1105 }
1106
1113 [[nodiscard]]
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;
1116 }
1117
1127 gpu static constexpr auto gcd(const Aeu& first, const Aeu& second, Aeu& bezoutX, Aeu& bezoutY) noexcept -> Aeu {
1128 Aeu gcd, quotient, remainder;
1129
1130 const auto ratio = first.compareTo(second);
1131 if(ratio == Comparison::greater) {
1132 gcd = second;
1133 divide(first, second, quotient, remainder);
1134 } else {
1135 gcd = first;
1136 divide(second, first, quotient, remainder);
1137 }
1138
1139 bezoutX = 0u; bezoutY = 1u;
1140 for(Aeu tX = 1u, tY = 0u; remainder != 0u; ) {
1141 Aeu tGcd = gcd; gcd = remainder;
1142
1143 Aeu t = bezoutX; bezoutX = tX - quotient * bezoutX; tX = t;
1144 t = bezoutY; bezoutY = tY - quotient * bezoutY; tY = t;
1145
1146 divide(tGcd, gcd, quotient, remainder);
1147 }
1148
1149 if(ratio != Comparison::greater)
1150 bezoutX.swap(bezoutY);
1151
1152 return gcd;
1153 }
1154
1162 gpu static constexpr auto gcd(const Aeu& first, const Aeu& second) noexcept -> Aeu {
1163 Aeu gcd, quotient, remainder;
1164
1165 const auto ratio = first.compareTo(second);
1166 if(ratio == Comparison::greater) {
1167 gcd = second;
1168 divide(first, second, quotient, remainder);
1169 } else {
1170 gcd = first;
1171 divide(second, first, quotient, remainder);
1172 }
1173
1174 while(remainder != 0u) {
1175 Aeu tGcd = gcd; gcd = remainder;
1176 divide(tGcd, gcd, quotient, remainder);
1177 }
1178
1179 return gcd;
1180 }
1181
1188 [[nodiscard]]
1189 gpu static constexpr auto lcm(const Aeu& first, const Aeu& second) noexcept -> Aeu { return first / gcd(first, second) * second; }
1190
1200 template <std::size_t powerBitness = bitness> [[nodiscard]]
1201 gpu static constexpr auto powm(const Aeu& base, const Aeu<powerBitness>& power, const Aeu& modulo) noexcept -> Aeu {
1202 if(base == 1u)
1203 return base;
1204 if(base == 0u)
1205 return { 1u };
1206
1207 Aeu output = 1u;
1208 auto [_, b] = divide(base, modulo);
1209
1210 for(unsigned iteration = 0; power.filledBlocksNumber() * blockBitLength != iteration; iteration++) {
1211 if(power.getBit(iteration)) {
1212 const auto [quotient, remainder] = divide(output * b, modulo);
1213 output = remainder;
1214 }
1215
1216 const auto [quotient, remainder] = divide(b * b, modulo);
1217 b = remainder;
1218 }
1219
1220 return output;
1221 }
1222
1223 [[nodiscard]]
1224 gpu static constexpr auto powm(const Aeu& base, const Aeu& power, const Aeu& mod) noexcept -> Aeu {
1225 Aeu output = 1u;
1226 auto [_, b] = divide(base, mod);
1227
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);
1231 output = remainder;
1232 }
1233
1234 const auto [quotient, remainder] = divide(b * b, mod);
1235 b = remainder;
1236 }
1237
1238 return output;
1239 }
1240
1247 [[nodiscard]]
1248 gpu static constexpr auto power2(std::size_t power) noexcept -> Aeu { Aeu result {}; result.setBit(power, true); return result; }
1249
1255 [[nodiscard]]
1256 gpu constexpr auto squareRoot() const noexcept -> Aeu {
1257 Aeu x, y = power2((bitCount() + 1) / 2);
1258
1259 do {
1260 x = y;
1261 y = (x + *this / x) >> 1u;
1262 } while (y < x);
1263
1264 return x;
1265 }
1266 /* ----------------------------------------------------------------------- */
1267
1268
1269 /* ----------------- @name Public input-output operators. ---------------- */
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;
1283
1284 std::size_t position = 0;
1285
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';
1290 } else {
1291 buffer[0] = L'0'; buffer[1] = L'b';
1292 }
1293 position += 2;
1294 } else if constexpr (base == 8) {
1295 if constexpr (std::is_same_v<Char, char>) {
1296 buffer[0] = '0'; buffer[1] = 'o';
1297 } else {
1298 buffer[0] = L'0'; buffer[1] = L'o';
1299 }
1300 position += 2;
1301 } else if constexpr (base == 16) {
1302 if constexpr (std::is_same_v<Char, char>) {
1303 buffer[0] = '0'; buffer[1] = 'x';
1304 } else {
1305 buffer[0] = L'0'; buffer[1] = L'x';
1306 }
1307 position += 2;
1308 }
1309 }
1310
1311 if(isZero()) {
1312 buffer[position++] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; }}();
1313 return position;
1314 }
1315
1316 if constexpr (base == 16) {
1317 std::size_t iter = blocks.size() - 1;
1318 for (; iter > 0 && blocks[iter] == 0; --iter)
1319 ;
1320
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]));
1324 for (; iter-- > 0;)
1325 position += static_cast<std::size_t>(snprintf(buffer + position, bufferSize - position, "%08X", blocks[iter]));
1326 } else {
1327 position += static_cast<std::size_t>(snprintf(buffer + position, bufferSize - position, "%x", blocks[iter]));
1328 for (; iter-- > 0;)
1329 position += static_cast<std::size_t>(snprintf(buffer + position, bufferSize - position, "%08x", blocks[iter]));
1330 }
1331 } else {
1332 if constexpr (hexUppercase) {
1333 position += static_cast<std::size_t>(swprintf(buffer + position, bufferSize - position, L"%X", blocks[iter]));
1334 for (; iter-- > 0;)
1335 position += static_cast<std::size_t>(swprintf(buffer + position, bufferSize - position, L"%08X", blocks[iter]));
1336 } else {
1337 position += static_cast<std::size_t>(swprintf(buffer + position, bufferSize - position, L"%x", blocks[iter]));
1338 for (; iter-- > 0;)
1339 position += static_cast<std::size_t>(swprintf(buffer + position, bufferSize - position, L"%08x", blocks[iter]));
1340 }
1341 }
1342 } else {
1343 const auto startPosition = position;
1344
1345 Aeu copy = *this;
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>());
1350 } else {
1351 buffer[position++] = static_cast<Char>(L'0' + remainder.template integralCast<byte>());
1352 }
1353 copy = quotient;
1354 }
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;
1360 }
1361 }
1362 buffer[position++] = Char {};
1363 return position;
1364 }
1365
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();
1380
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)
1384 ss << [&tBase] {
1385 if constexpr (std::is_same_v<Char, char>) {
1386 return tBase == 8 ? "0o" : "0x";
1387 } else {
1388 return tBase == 8 ? L"0o" : L"0x";
1389 }
1390 } () << std::noshowbase ;
1391 return tBase;
1392 } (flags & std::ios::basefield, os, flags & std::ios::showbase);
1393
1394 if(number.isZero())
1395 return os << '0';
1396
1397 if(base == 16) {
1398 std::size_t iter = number.blocks.size() - 1;
1399 for(; iter > 0 && number.blocks[iter] == 0; --iter)
1400 ;
1401
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];
1406 }
1407 } else {
1408 /* Well, here we use a pre-calculated magic number to ratio the length of numbers in decimal or octal notation according to bitness.
1409 * * It is 2.95-98 for octal and 3.2 for decimal. */
1410 constexpr auto bufferSize = static_cast<std::size_t>(static_cast<double>(bitness) / 2.95);
1411 Char buffer [bufferSize] {}; std::size_t filled = 0;
1412
1413 Aeu copy = number;
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>());
1417 copy = quotient;
1418 }
1419
1420 for(; filled > 0; --filled)
1421 os << buffer[filled - 1];
1422 }
1423
1424 return os;
1425 }
1426
1427
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 {
1438 blocks = {};
1439 if(bigEndian) {
1440 for(auto it = blocks.rbegin(); it != blocks.rend(); ++it)
1441 if(!is.read(reinterpret_cast<char*>(&*it), sizeof(block))) break;
1442 } else {
1443 for(auto& tBlock: blocks)
1444 if(!is.read(reinterpret_cast<char*>(&tBlock), sizeof(block))) break;
1445 }
1446 }
1447
1448
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 {
1457 if(bigEndian) {
1458 for(auto it = blocks.rbegin(); it != blocks.rend(); ++it)
1459 if(!os.write(reinterpret_cast<const char*>(&*it), sizeof(block))) break;
1460 } else {
1461 for(auto& block: blocks)
1462 if(!os.write(reinterpret_cast<const char*>(&block), sizeof(block))) break;
1463 }
1464 }
1465 /* ----------------------------------------------------------------------- */
1466
1467
1468 /* -------------------- @name Public casting operators. ------------------ */
1474 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
1475 gpu constexpr auto integralCast() const noexcept -> Integral {
1476 const uint64_t value = (static_cast<uint64_t>(blocks[1]) << blockBitLength) | static_cast<uint64_t>(blocks[0]);
1477 return static_cast<Integral>(value);
1478 }
1479
1488 template <std::size_t newBitness> requires (newBitness != bitness) [[nodiscard]]
1489 gpu constexpr auto precisionCast() const noexcept -> Aeu<newBitness> {
1490 Aeu<newBitness> result {};
1491
1492 const std::size_t blockBoarder = (newBitness > bitness ? Aeu<bitness>::totalBlocksNumber() : Aeu<newBitness>::totalBlocksNumber());
1493 for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
1494 result.setBlock(blockIdx, getBlock(blockIdx));
1495
1496 return result;
1497 }
1498 /* ----------------------------------------------------------------------- */
1499
1500
1501#if defined __CUDACC__
1502 /* ------------------- @name Atomic-like CUDA operators. ----------------- */
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]);
1512 }
1513
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]));
1523 }
1524 /* ----------------------------------------------------------------------- */
1525#endif
1526};
1527
1528/* -------------------------------------------- @name Type-definitions ------------------------------------------- */
1533
1538
1543
1548
1553
1558
1563
1568
1573
1578
1583/* ---------------------------------------------------------------------------------------------------------------- */
1584
1585/* ------------------------------------------ @name Integral conversions ----------------------------------------- */
1592template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1593gpu constexpr auto operator+(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) + value; }
1594
1601template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1602gpu constexpr auto operator-(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) - value; }
1603
1610template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1611gpu constexpr auto operator*(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) * value; }
1612
1619template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1620gpu constexpr auto operator/(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) / value; }
1621
1628template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1629gpu constexpr auto operator%(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) % value; }
1630
1637template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1638gpu constexpr auto operator^(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) ^ value; }
1639
1646template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1647gpu constexpr auto operator&(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) & value; }
1648
1655template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1656gpu constexpr auto operator|(Integral number, const Aeu<bitness>& value) noexcept { return Aeu<bitness>(number) | value; }
1657/* ---------------------------------------------------------------------------------------------------------------- */
1658
1659#endif //AEU_MULTIPRECISION
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 &quotient, 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