Aesi Multiprecision
C++ class library of long integer arithmetic for GPU parallelization
Loading...
Searching...
No Matches
Aesi.h
Go to the documentation of this file.
1
31#ifndef AESI_MULTIPRECISION
32#define AESI_MULTIPRECISION
33
35#include "Aeu.h"
37
38namespace {
39 enum class Sign { Zero = 0, Positive = 1, Negative = -1 };
40
41 template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
42 Sign traverseDashes(const Char* ptr, std::size_t);
43
44 template <>
45 Sign traverseDashes(const char* ptr, std::size_t size) {
46 std::byte positive { 1 };
47 for(std::size_t i = 0; i < size; ++i)
48 if(ptr[i] == '-') positive ^= std::byte {1};
49 return positive == std::byte {1} ? Sign::Positive : Sign::Negative;
50 }
51
52 template <>
53 Sign traverseDashes(const wchar_t* ptr, std::size_t size) {
54 std::byte positive { 1 };
55 for(std::size_t i = 0; i < size; ++i)
56 if(ptr[i] == L'-') positive ^= std::byte {1};
57 return positive == std::byte {1} ? Sign::Positive : Sign::Negative;
58 }
59}
66template <std::size_t bitness = 512> requires (bitness % blockBitLength == 0)
67class Aesi final {
68 /* -------------------------- @name Class members. ----------------------- */
69 Sign sign;
70
71 using Base = Aeu<bitness>;
72 Base base;
73 /* ----------------------------------------------------------------------- */
74
75 gpu constexpr Aesi(Sign withSign, Base withBase): sign { withSign }, base { withBase } {}
76
77public:
78 /* --------------------- @name Different constructors. ------------------- */
82 gpu constexpr Aesi() noexcept = default;
83
87 gpu constexpr ~Aesi() noexcept = default;
88
93 gpu constexpr Aesi(const Aesi& copy) noexcept = default;
94
99 template <typename Integral> requires (std::is_integral_v<Integral>)
100 gpu constexpr Aesi(Integral value) noexcept {
101 using enum Sign;
102 if(value < 0) {
103 value *= -1;
104 base = Base(static_cast<unsigned long long>(value));
105 sign = Negative;
106 } else if(value > 0) {
107 base = Base(static_cast<unsigned long long>(value));
108 sign = Positive;
109 } else
110 sign = Zero;
111 }
112
120 template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
121 gpu constexpr Aesi(const Char* ptr, std::size_t size) noexcept : base(ptr, size) {
122 if(!base.isZero())
123 sign = traverseDashes(ptr, size);
124 else sign = Sign::Zero;
125 }
126
131 template <typename Char, std::size_t arrayLength> requires (arrayLength > 1 && (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>))
132 gpu constexpr Aesi(const Char (&literal)[arrayLength]) noexcept : Aesi(literal, arrayLength) {}
133
138 template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
139 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
140 gpu constexpr Aesi(String&& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}
141
142 template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
143 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
144 gpu constexpr Aesi(const String& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}
145
150 explicit gpu constexpr Aesi(const Aeu<bitness>& value) : sign(Sign::Positive), base(value) {}
151
152#ifdef AESI_CRYPTOPP_INTEGRATION
157 constexpr Aesi(const CryptoPP::Integer& number) {
158 using enum Sign;
159 if(number.IsZero())
160 sign = Zero;
161 else {
162 base = number;
163 if(number.IsNegative())
164 sign = Negative;
165 else sign = Positive;
166 }
167 }
168#endif
169
170#ifdef AESI_GMP_INTEGRATION
175 constexpr Aesi(const mpz_class& number) {
176 using enum Sign;
177 if(number == 0)
178 sign = Zero;
179 else {
180 base = number;
181 if(number < 0)
182 sign = Negative;
183 else sign = Positive;
184 }
185 }
186#endif
187
192 template <typename Integral> requires (std::is_signed_v<Integral>)
193 gpu constexpr Aesi& operator=(Integral value) noexcept {
194 using enum Sign;
195 if(value != 0) {
196 if(value < 0) {
197 sign = Negative;
198 value *= -1;
199 } else sign = Positive;
200 base = static_cast<unsigned long long>(value);
201 } else sign = Zero;
202 return *this;
203 }
204
209 gpu constexpr Aesi& operator=(const Aesi& other) noexcept { base = other.base; sign = other.sign; return *this; }
210 /* ----------------------------------------------------------------------- */
211
212
213 /* --------------------- @name Arithmetic operators. --------------------- */
214 /* ------------------------- @name Unary operators. -------------------------- */
220 gpu constexpr auto operator+() const noexcept -> Aesi { return *this; }
221
226 [[nodiscard]]
227 gpu constexpr auto operator-() const noexcept -> Aesi { Aesi copy = *this; copy.inverse(); return copy; }
228
233 gpu constexpr auto operator++() noexcept -> Aesi& {
234 using enum Sign;
235 if(sign == Negative) {
236 --base; if(base.isZero()) sign = Zero;
237 } else if(sign == Positive) {
238 ++base;
239 } else { base = 1u; sign = Positive; }
240 return *this;
241 }
242
247 gpu constexpr auto operator++(int) & noexcept -> Aesi { Aesi old = *this; operator++(); return old; }
248
253 gpu constexpr auto operator--() noexcept -> Aesi& {
254 using enum Sign;
255 if(sign == Negative) {
256 ++base;
257 } else if(sign == Positive) {
258 --base; if(base.isZero()) sign = Zero;
259 } else { base = 1u; sign = Negative; }
260 return *this;
261 }
262
267 gpu constexpr auto operator--(int) & noexcept -> Aesi { Aesi old = *this; operator--(); return old; }
268 /* --------------------------------------------------------------------------- */
269
270 /* ------------------------ @name Addition operators. ------------------------ */
277 [[nodiscard]]
278 gpu constexpr friend auto operator+(const Aesi& addition, const Aesi& addendum) noexcept -> Aesi {
279 Aesi result = addition; result += addendum; return result;
280 }
281
288 gpu constexpr friend auto operator+=(Aesi& addition, const Aesi& addendum) noexcept -> Aesi& {
289 using enum Sign;
290 Sign& lSign = addition.sign; const Sign& rSign = addendum.sign;
291 Base& lBase = addition.base; const Base& rBase = addendum.base;
292
293 if(rSign == Zero)
294 return addition;
295 else if(lSign == Zero)
296 return addition = addendum;
297 else if(lSign == rSign) {
298 lBase += rBase;
299 return addition;
300 }
301
302 if(lSign == Positive) {
303 switch(lBase.compareTo(rBase)) {
304 using enum Comparison;
305 case greater: {
306 lBase -= rBase;
307 return addition;
308 }
309 case less: {
310 lBase = rBase - lBase;
311 lSign = Negative;
312 return addition;
313 }
314 default: {
315 lSign = Zero;
316 return addition;
317 }
318 }
319 } else {
320 switch(const auto ratio = lBase.compareTo(rBase)) {
321 using enum Comparison;
322 case greater: {
323 lBase -= rBase;
324 return addition;
325 }
326 case less: {
327 lBase = rBase - lBase;
328 lSign = Positive;
329 return addition;
330 }
331 default: {
332 lSign = Zero;
333 return addition;
334 }
335 }
336 }
337 }
338 /* --------------------------------------------------------------------------- */
339
340 /* ----------------------- @name Subtraction operators. ---------------------- */
347 [[nodiscard]]
348 gpu constexpr friend auto operator-(const Aesi& subtraction, const Aesi& subtrahend) noexcept -> Aesi {
349 Aesi result = subtraction; result -= subtrahend; return result;
350 }
351
358 gpu constexpr friend auto operator-=(Aesi& subtraction, const Aesi& subtrahend) noexcept -> Aesi& {
359 using enum Sign;
360 Sign& lSign = subtraction.sign; const Sign& rSign = subtrahend.sign;
361 Base& lBase = subtraction.base; const Base& rBase = subtrahend.base;
362
363 if(rSign == Zero)
364 return subtraction;
365 if(lSign == Zero) {
366 subtraction = subtrahend;
367 subtraction.inverse();
368 return subtraction;
369 }
370
371 if(lSign == Positive) {
372 if(rSign == Positive) {
373 switch(lBase.compareTo(rBase)) {
374 using enum Comparison;
375 case greater: {
376 lBase -= rBase;
377 return subtraction;
378 }
379 case less: {
380 lBase = rBase - lBase;
381 lSign = Negative;
382 return subtraction;
383 }
384 default: {
385 lSign = Zero;
386 return subtraction;
387 }
388 }
389 } else {
390 lBase += rBase;
391 return subtraction;
392 }
393 } else {
394 if(rSign == Negative) {
395 switch(lBase.compareTo(rBase)) {
396 using enum Comparison;
397 case greater: {
398 lBase -= rBase;
399 return subtraction;
400 }
401 case less: {
402 lBase = rBase - lBase;
403 lSign = Positive;
404 return subtraction;
405 }
406 default: {
407 lSign = Zero;
408 return subtraction;
409 }
410 }
411 } else {
412 lBase += rBase;
413 return subtraction;
414 }
415 }
416 }
417 /* --------------------------------------------------------------------------- */
418
419 /* --------------------- @name Multiplication operators. --------------------- */
426 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
427 gpu constexpr friend auto operator*(const Aesi& multiplication, Integral factor) noexcept -> Aesi {
428 Aesi result = multiplication; result *= factor; return result;
429 }
430
437 [[nodiscard]]
438 gpu constexpr friend auto operator*(const Aesi& multiplication, const Aesi& factor) noexcept -> Aesi {
439 Aesi result = multiplication; result *= factor; return result;
440 }
441
448 template <typename Integral> requires (std::is_integral_v<Integral>)
449 gpu constexpr friend auto operator*=(Aesi& multiplication, Integral factor) noexcept -> Aesi& {
450 using enum Sign;
451 if(factor == 0) {
452 multiplication.sign = Zero;
453 } else {
454 if(factor < 0) {
455 multiplication.inverse();
456 factor *= -1;
457 }
458 multiplication.base *= static_cast<unsigned long long>(factor);
459 }
460 return multiplication;
461 }
462
469 gpu constexpr friend auto operator*=(Aesi& multiplication, const Aesi& factor) noexcept -> Aesi& {
470 using enum Sign;
471 if(factor.isZero()) {
472 multiplication.sign = Zero;
473 } else {
474 if(factor.isNegative())
475 multiplication.inverse();
476 multiplication.base *= factor.base;
477 }
478 return multiplication;
479 }
480 /* --------------------------------------------------------------------------- */
481
482 /* ------------------------ @name Division operators. ------------------------ */
490 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
491 gpu constexpr friend auto operator/(const Aesi& division, Integral divisor) noexcept -> Aesi {
492 Aesi result = division; result /= divisor; return result;
493 }
494
502 [[nodiscard]]
503 gpu constexpr friend auto operator/(const Aesi& division, const Aesi& divisor) noexcept -> Aesi {
504 Aesi result = division; result /= divisor; return result;
505 }
506
514 template <typename Integral> requires (std::is_integral_v<Integral>)
515 gpu constexpr friend auto operator/=(Aesi& division, Integral divisor) noexcept -> Aesi& {
516 using enum Sign;
517 if(divisor == 0) {
518 division.sign = Zero;
519 } else {
520 if(divisor < 0) {
521 division.inverse();
522 divisor *= -1;
523 }
524 division.base /= static_cast<unsigned long long>(divisor);
525 if(division.base.isZero()) division.sign = Zero;
526 }
527 return division;
528 }
529
537 gpu constexpr friend auto operator/=(Aesi& division, const Aesi& divisor) noexcept -> Aesi& {
538 using enum Sign;
539 if(divisor.isZero()) {
540 division.sign = Zero;
541 } else {
542 if(divisor.isNegative())
543 division.inverse();
544 division.base /= divisor.base;
545 if(division.base.isZero()) division.sign = Zero;
546 }
547 return division;
548 }
549 /* --------------------------------------------------------------------------- */
550
551 /* ------------------------- @name Modulo operators. ------------------------- */
559 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
560 gpu constexpr friend auto operator%(const Aesi& modulation, Integral modulo) noexcept -> Aesi {
561 Aesi result = modulation; result %= modulo; return result;
562 }
563
572 [[nodiscard]]
573 gpu constexpr friend auto operator%(const Aesi& modulation, const Aesi& modulo) noexcept -> Aesi {
574 Aesi result = modulation; result %= modulo; return result;
575 }
576
584 template <typename Integral> requires (std::is_integral_v<Integral>)
585 gpu constexpr friend auto operator%=(Aesi& modulation, Integral modulo) noexcept -> Aesi& {
586 using enum Sign;
587 if(modulo == 0) {
588 modulation.sign = Zero;
589 } else {
590 if(modulo < 0) {
591 modulation.inverse();
592 modulo *= -1;
593 }
594 modulation.base %= static_cast<unsigned long long>(modulo);
595 }
596 return modulation;
597 }
598
607 gpu constexpr friend auto operator%=(Aesi& modulation, const Aesi& modulo) noexcept -> Aesi& {
608 if(modulo.isZero())
609 return modulation;
610
611 if(modulo.isNegative())
612 modulation.inverse();
613 modulation.base %= modulo.base;
614 if(modulation.base.isZero())
615 modulation.sign = Sign::Zero;
616
617 return modulation;
618 }
619 /* --------------------------------------------------------------------------- */
620 /* ----------------------------------------------------------------------- */
621
622 /* --------------------- @name Comparison operators. --------------------- */
623 /* ------------------------ @name Equality operators. ------------------------ */
630 template <typename Integral> requires (std::is_integral_v<Integral>)
631 gpu constexpr friend auto operator==(const Aesi& our, Integral integral) noexcept -> bool {
632 return our.compareTo(integral) == Comparison::equal;
633 }
634
641 gpu constexpr friend auto operator==(const Aesi& our, const Aesi& other) noexcept -> bool = default;
642
649 template <std::size_t otherBitness> requires (otherBitness != bitness)
650 gpu constexpr friend auto operator==(const Aesi& our, const Aesi<otherBitness>& other) noexcept -> bool {
651 return our.precisionCast<otherBitness>() == other;
652 }
653 /* --------------------------------------------------------------------------- */
654
655
656 /* ----------------------- @name Comparison operators. ----------------------- */
662 template <typename Integral> requires (std::is_integral_v<Integral>)
663 gpu constexpr auto compareTo(Integral integral) const noexcept -> Comparison {
664 using enum Sign; using enum Comparison;
665 if(integral == 0) {
666 switch(sign) {
667 case Positive:
668 return greater;
669 case Negative:
670 return less;
671 default:
672 return equal;
673 }
674 } else if(integral < 0) {
675 if(sign == Negative)
676 switch(base.compareTo(static_cast<unsigned long long>(integral * -1))) {
677 using enum Comparison;
678 case greater:
679 return less;
680 case less:
681 return greater;
682 default:
683 return equal;
684 }
685 else return greater;
686 } else {
687 if(sign == Positive)
688 return base.compareTo(static_cast<unsigned long long>(integral));
689 return less;
690 }
691 }
692
698 template <std::size_t otherBitness = bitness> [[nodiscard]]
699 gpu constexpr auto compareTo(const Aesi<otherBitness>& value) const noexcept -> Comparison {
700 return precisionCast<otherBitness>().compareTo(value);
701 }
702
708 [[nodiscard]]
709 gpu constexpr auto compareTo(const Aesi& value) const noexcept -> Comparison {
710 using enum Sign; using enum Comparison;
711 if(value.isZero()) {
712 switch(sign) {
713 case Positive:
714 return greater;
715 case Negative:
716 return less;
717 default:
718 return equal;
719 }
720 }
721
722 if(value.isNegative()) {
723 if(sign == Negative)
724 switch(base.compareTo(value.base)) {
725 case greater:
726 return less;
727 case less:
728 return greater;
729 default:
730 return equal;
731 }
732 return greater;
733 }
734
735 if(sign == Positive)
736 return base.compareTo(value.base);
737 return less;
738 }
739 /* --------------------------------------------------------------------------- */
740
741 /* ------------------------ @name Spaceship operators. ----------------------- */
742#if (defined(__CUDACC__) || __cplusplus < 202002L || defined (PRE_CPP_20)) && !defined DOXYGEN_SKIP
746 gpu constexpr auto operator!=(const Aeu& value) const noexcept -> bool {
747 return !this->operator==(value);
748 }
749 gpu constexpr auto operator<(const Aeu& value) const noexcept -> bool {
750 return this->compareTo(value) == Comparison::less;
751 }
752 gpu constexpr auto operator<=(const Aeu& value) const noexcept -> bool {
753 return !this->operator>(value);
754 }
755 gpu constexpr auto operator>(const Aeu& value) const noexcept -> bool {
756 return this->compareTo(value) == Comparison::greater;
757 }
758 gpu constexpr auto operator>=(const Aeu& value) const noexcept -> bool {
759 return !this->operator<(value);
760 }
761#else
768 gpu constexpr auto operator<=>(const Aesi& other) const noexcept -> std::strong_ordering {
769 switch(this->compareTo(other)) {
770 using enum Comparison;
771 case less:
772 return std::strong_ordering::less;
773 case greater:
774 return std::strong_ordering::greater;
775 case equal:
776 return std::strong_ordering::equal;
777 default:
778 return std::strong_ordering::equivalent;
779 }
780 }
781
788 template <typename Object>
789 gpu constexpr auto operator<=>(const Object& other) const noexcept -> std::strong_ordering {
790 switch(this->compareTo(other)) {
791 using enum Comparison;
792 case less:
793 return std::strong_ordering::less;
794 case greater:
795 return std::strong_ordering::greater;
796 case equal:
797 return std::strong_ordering::equal;
798 default:
799 return std::strong_ordering::equivalent;
800 }
801 };
802#endif
803 /* --------------------------------------------------------------------------- */
804 /* ----------------------------------------------------------------------- */
805
806 /* ---------------------- @name Supporting methods. ---------------------- */
813 gpu constexpr auto setBit(std::size_t index, bool bit) noexcept -> void { return base.setBit(index, bit); }
814
821 [[nodiscard]]
822 gpu constexpr auto getBit(std::size_t index) const noexcept -> bool { return base.getBit(index); }
823
830 gpu constexpr auto setByte(std::size_t index, byte byte) noexcept -> void { return base.setByte(index, byte); }
831
838 [[nodiscard]]
839 gpu constexpr auto getByte(std::size_t index) const noexcept -> byte { return base.getByte(index); }
840
847 gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void { return base.setBlock(index, block); }
848
855 [[nodiscard]]
856 gpu constexpr auto getBlock(std::size_t index) const noexcept -> block { return base.getBlock(index); }
857
862 [[nodiscard]]
863 gpu constexpr auto byteCount() const noexcept -> std::size_t { return base.byteCount(); }
864
869 [[nodiscard]]
870 gpu constexpr auto bitCount() const noexcept -> std::size_t { return base.bitCount(); }
871
876 [[nodiscard]]
877 gpu constexpr auto isOdd() const noexcept -> bool { return base.isOdd(); }
878
883 [[nodiscard]]
884 gpu constexpr auto isEven() const noexcept -> bool { return base.isEven(); }
885
890 [[nodiscard]]
891 gpu constexpr auto isZero() const noexcept -> bool { return sign == Sign::Zero; }
892
897 [[nodiscard]]
898 gpu constexpr auto isPositive() const noexcept -> bool { return sign == Sign::Positive; }
899
904 [[nodiscard]]
905 gpu constexpr auto isNegative() const noexcept -> bool { return sign == Sign::Negative; }
906
911 [[nodiscard]]
912 gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t { return base.filledBlocksNumber(); }
913
918 [[nodiscard]]
919 gpu static constexpr auto getBitness() noexcept -> std::size_t { return bitness; }
920
925 [[nodiscard]]
926 gpu static constexpr auto totalBlocksNumber() noexcept -> std::size_t { return Aeu<bitness>::totalBlocksNumber(); }
927
932 gpu constexpr auto swap(Aesi& other) noexcept -> void {
933 Sign tSign = sign; sign = other.sign; other.sign = tSign;
934 base.swap(other.base);
935 }
936
941 gpu constexpr auto inverse() noexcept -> void {
942 using enum Sign;
943 sign = (sign == Zero ? Zero : (sign == Negative ? Positive : Negative));
944 }
945 /* ----------------------------------------------------------------------- */
946
947 /* -------------- @name Public arithmetic and number theory. ------------- */
956 gpu static constexpr auto divide(const Aesi& number, const Aesi& divisor, Aesi& quotient, Aesi& remainder) noexcept -> void {
957 using enum Sign;
958 if(number.sign == Zero || divisor.sign == Zero) {
959 quotient.sign = Zero;
960 remainder.sign = Zero;
961 return;
962 }
963
964 Base::divide(number.base, divisor.base, quotient.base, remainder.base);
965 if(number.sign == Positive) {
966 if(divisor.sign == Positive) {
967 quotient.sign = Positive;
968 remainder.sign = Positive;
969 } else {
970 quotient.sign = Negative;
971 remainder.sign = Positive;
972 }
973 } else {
974 if(divisor.sign == Positive) {
975 quotient.sign = Negative;
976 remainder.sign = Negative;
977 } else {
978 quotient.sign = Positive;
979 remainder.sign = Negative;
980 }
981 }
982
983 if(quotient.base.isZero())
984 quotient.sign = Zero;
985 if(remainder.base.isZero())
986 remainder.sign = Zero;
987 }
988
994 [[nodiscard]]
995 gpu constexpr auto squareRoot() const noexcept -> Aesi {
996 using enum Sign;
997 if(sign == Positive)
998 return Aesi { Positive, base.squareRoot() };
999 Aesi result; result.sign = Zero; return result;
1000 }
1001
1006 [[nodiscard]]
1007 gpu static constexpr auto power2(std::size_t power) noexcept -> Aesi {
1008 using enum Sign;
1009 Aesi result { Positive, Aeu<bitness>::power2(power) };
1010 if(result.base.isZero())
1011 result.sign = Zero;
1012 return result;
1013 }
1014 /* ----------------------------------------------------------------------- */
1015
1020 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
1021 gpu constexpr auto integralCast() const noexcept -> Integral {
1022 using enum Sign;
1023 if(sign == Zero)
1024 return Integral(0);
1025
1026 if constexpr (std::is_signed_v<Integral>) {
1027 if(sign == Negative)
1028 return base.template integralCast<Integral>() * -1;
1029 }
1030
1031 return base.template integralCast<Integral>();
1032 }
1033
1038 template <std::size_t newBitness> requires (newBitness != bitness) [[nodiscard]]
1039 gpu constexpr auto precisionCast() const noexcept -> Aesi<newBitness> {
1040 using enum Sign;
1041 if(sign != Zero) {
1042 Aesi<newBitness> result = 1;
1043
1044 const std::size_t blockBoarder = (newBitness > bitness ? totalBlocksNumber() : Aesi<newBitness>::totalBlocksNumber());
1045 for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
1046 result.setBlock(blockIdx, getBlock(blockIdx));
1047
1048 if(sign == Negative)
1049 result.inverse();
1050
1051 return result;
1052 }
1053
1054 return Aesi<newBitness> {};
1055 }
1056
1061 gpu constexpr auto unsignedCast() const noexcept -> Aeu<bitness> { return base; }
1062
1063 /* ----------------- @name Public input-output operators. ---------------- */
1074 template <byte notation, typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t> && (notation == 2 || notation == 8 || notation == 10 || notation == 16))
1075 gpu constexpr auto getString(Char* buffer, std::size_t bufferSize, bool showBase = false, bool hexUppercase = false) const noexcept -> std::size_t {
1076 using enum Sign;
1077
1078 if(sign != Zero) {
1079 if(sign == Negative && bufferSize > 0) {
1080 *buffer++ = [] { if constexpr (std::is_same_v<Char, char>) { return '-'; } else { return L'-'; } } ();
1081 --bufferSize;
1082 }
1083 return base.template getString<notation, Char>(buffer, bufferSize, showBase, hexUppercase);
1084 }
1085
1086 if(showBase) {
1087 switch(notation) {
1088 case 2: {
1089 if(bufferSize < 3) return 0;
1090 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1091 buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'b'; } else { return L'b'; } } ();
1092 buffer[2] = buffer[0];
1093 return 3;
1094 }
1095 case 8: {
1096 if(bufferSize < 3) return 0;
1097 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1098 buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'o'; } else { return L'o'; } } ();
1099 buffer[2] = buffer[0];
1100 return 3;
1101 }
1102 case 16: {
1103 if(bufferSize < 3) return 0;
1104 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1105 buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'x'; } else { return L'x'; } } ();
1106 buffer[2] = buffer[0];
1107 return 3;
1108 }
1109 default: {
1110 if(bufferSize < 1) return 0;
1111 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1112 return 1;
1113 }
1114 }
1115 }
1116
1117 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1118 return 1;
1119 }
1120
1132 template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1133 friend constexpr auto operator<<(std::basic_ostream<Char>& os, const Aesi& number) -> std::basic_ostream<Char>& {
1134 using enum Sign;
1135 if(number.sign != Zero) {
1136 if(number.sign == Negative)
1137 os << [] { if constexpr (std::is_same_v<Char, char>) { return '-'; } else { return L'-'; } } ();
1138 return os << number.base;
1139 }
1140 return os << '0';
1141 }
1142 /* ----------------------------------------------------------------------- */
1143
1144#if defined __CUDACC__ || defined DOXYGEN_SKIP
1151 __device__ constexpr auto tryAtomicSet(const Aesi& value) noexcept -> void {
1152 base.tryAtomicSet(value.base);
1153 sign = value.sign; /* TODO: Make enum substitution using existing CUDA atomics */
1154 }
1155
1162 __device__ constexpr auto tryAtomicExchange(const Aesi& value) noexcept -> void {
1163 base.tryAtomicExchange(value.base);
1164 sign = value.sign; /* TODO: Make enum substitution using existing CUDA atomics */
1165 }
1166#endif
1167};
1168
1169/* -------------------------------------------- @name Type-definitions ------------------------------------------- */
1174
1179
1184
1189
1194
1199
1204
1209
1214
1219
1224/* ---------------------------------------------------------------------------------------------------------------- */
1225
1226/* ------------------------------------------ @name Integral conversions ----------------------------------------- */
1233template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1234gpu constexpr auto operator+(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) + value; }
1235
1242template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1243gpu constexpr auto operator-(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) - value; }
1244
1251template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1252gpu constexpr auto operator*(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) * value; }
1253
1260template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1261gpu constexpr auto operator/(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) / value; }
1262
1269template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1270gpu constexpr auto operator%(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) % value; }
1271
1278template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1279gpu constexpr auto operator^(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) ^ value; }
1280
1287template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1288gpu constexpr auto operator&(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) & value; }
1289
1296template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1297gpu constexpr auto operator|(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) | value; }
1298/* ---------------------------------------------------------------------------------------------------------------- */
1299
1300#endif //AESI_MULTIPRECISION
Long precision unsigned integer with arithmetic operations.
Long precision signed integer.
Definition Aesi.h:67
gpu constexpr friend auto operator%(const Aesi &modulation, const Aesi &modulo) noexcept -> Aesi
Modulo operator.
Definition Aesi.h:573
gpu constexpr auto byteCount() const noexcept -> std::size_t
Get amount of non-empty bytes in number right to left.
Definition Aesi.h:863
gpu constexpr auto operator<=>(const Object &other) const noexcept -> std::strong_ordering
Three-way comparison operator for numbers of different precision and built-in integral types.
Definition Aesi.h:789
gpu constexpr friend auto operator/=(Aesi &division, const Aesi &divisor) noexcept -> Aesi &
Assignment division operator.
Definition Aesi.h:537
gpu constexpr auto swap(Aesi &other) noexcept -> void
Make swap between two objects.
Definition Aesi.h:932
gpu constexpr auto inverse() noexcept -> void
Invertes number's bitness.
Definition Aesi.h:941
gpu constexpr Aesi(const Aeu< bitness > &value)
Unsigned integer conversion.
Definition Aesi.h:150
gpu constexpr auto operator++(int) &noexcept -> Aesi
Postfix increment operator.
Definition Aesi.h:247
gpu constexpr auto operator--(int) &noexcept -> Aesi
Postfix decrement operator.
Definition Aesi.h:267
gpu constexpr Aesi & operator=(const Aesi &other) noexcept
Copy assignment operator.
Definition Aesi.h:209
gpu constexpr friend auto operator-=(Aesi &subtraction, const Aesi &subtrahend) noexcept -> Aesi &
Subtraction assignment operator.
Definition Aesi.h:358
gpu constexpr auto operator--() noexcept -> Aesi &
Prefix decrement operator.
Definition Aesi.h:253
gpu constexpr auto compareTo(const Aesi< otherBitness > &value) const noexcept -> Comparison
Different precision comparison operator.
Definition Aesi.h:699
__device__ constexpr auto tryAtomicSet(const Aesi &value) noexcept -> void
Atomicity-oriented object assignment operator.
Definition Aesi.h:1151
gpu constexpr friend auto operator*(const Aesi &multiplication, const Aesi &factor) noexcept -> Aesi
Multiplication operator.
Definition Aesi.h:438
gpu constexpr auto getString(Char *buffer, std::size_t bufferSize, bool showBase=false, bool hexUppercase=false) const noexcept -> std::size_t
Character buffer output operator.
Definition Aesi.h:1075
gpu constexpr auto operator++() noexcept -> Aesi &
Prefix increment operator.
Definition Aesi.h:233
gpu constexpr friend auto operator%=(Aesi &modulation, const Aesi &modulo) noexcept -> Aesi &
Modulo assignment operator.
Definition Aesi.h:607
gpu constexpr auto operator<=>(const Aesi &other) const noexcept -> std::strong_ordering
Three-way comparison operator.
Definition Aesi.h:768
gpu constexpr Aesi(String &&stringView) noexcept
String / String-view constructor.
Definition Aesi.h:140
gpu constexpr friend auto operator+(const Aesi &addition, const Aesi &addendum) noexcept -> Aesi
Addition operator.
Definition Aesi.h:278
static gpu constexpr auto power2(std::size_t power) noexcept -> Aesi
Fast exponentiation of 2.
Definition Aesi.h:1007
gpu constexpr auto integralCast() const noexcept -> Integral
Cast for built-in integral types.
Definition Aesi.h:1021
gpu constexpr auto precisionCast() const noexcept -> Aesi< newBitness >
Number's precision cast.
Definition Aesi.h:1039
gpu constexpr friend auto operator+=(Aesi &addition, const Aesi &addendum) noexcept -> Aesi &
Addition assignment operator.
Definition Aesi.h:288
gpu constexpr friend auto operator-(const Aesi &subtraction, const Aesi &subtrahend) noexcept -> Aesi
Subtraction operator.
Definition Aesi.h:348
gpu constexpr friend auto operator/(const Aesi &division, const Aesi &divisor) noexcept -> Aesi
Division operator.
Definition Aesi.h:503
gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void
Set block in number by index starting from the right.
Definition Aesi.h:847
gpu constexpr auto isOdd() const noexcept -> bool
Check whether number is odd.
Definition Aesi.h:877
static gpu constexpr auto getBitness() noexcept -> std::size_t
Get number's precision.
Definition Aesi.h:919
__device__ constexpr auto tryAtomicExchange(const Aesi &value) noexcept -> void
Atomicity-oriented object exchangement operator.
Definition Aesi.h:1162
gpu constexpr auto getBlock(std::size_t index) const noexcept -> block
Get block in number by index starting from the right.
Definition Aesi.h:856
gpu constexpr Aesi(const Char *ptr, std::size_t size) noexcept
Pointer-based character constructor.
Definition Aesi.h:121
gpu constexpr auto isNegative() const noexcept -> bool
Check whether number is negative.
Definition Aesi.h:905
gpu constexpr auto isEven() const noexcept -> bool
Check whether number is even.
Definition Aesi.h:884
gpu constexpr auto isZero() const noexcept -> bool
Check whether number is zero.
Definition Aesi.h:891
gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t
Get number of non-empty blocks inside object starting from the right.
Definition Aesi.h:912
gpu constexpr auto getByte(std::size_t index) const noexcept -> byte
Get byte in number by index starting from the right.
Definition Aesi.h:839
gpu constexpr auto operator-() const noexcept -> Aesi
Unary minus operator.
Definition Aesi.h:227
gpu constexpr auto getBit(std::size_t index) const noexcept -> bool
Get bit in number by index starting from the right.
Definition Aesi.h:822
gpu constexpr auto squareRoot() const noexcept -> Aesi
Square root.
Definition Aesi.h:995
gpu constexpr auto compareTo(const Aesi &value) const noexcept -> Comparison
Comparison operator.
Definition Aesi.h:709
gpu constexpr auto compareTo(Integral integral) const noexcept -> Comparison
Comparison operator for built-in types.
Definition Aesi.h:663
gpu constexpr auto setByte(std::size_t index, byte byte) noexcept -> void
Set byte in number by index starting from the right.
Definition Aesi.h:830
static gpu constexpr auto totalBlocksNumber() noexcept -> std::size_t
Get the number of blocks (length of array of uint32_t integers) inside object.
Definition Aesi.h:926
gpu constexpr auto isPositive() const noexcept -> bool
Check whether number is positive.
Definition Aesi.h:898
static gpu constexpr auto divide(const Aesi &number, const Aesi &divisor, Aesi &quotient, Aesi &remainder) noexcept -> void
Integral division.
Definition Aesi.h:956
gpu constexpr auto setBit(std::size_t index, bool bit) noexcept -> void
Set bit in number by index starting from the right.
Definition Aesi.h:813
gpu constexpr auto unsignedCast() const noexcept -> Aeu< bitness >
Unsigned cast.
Definition Aesi.h:1061
gpu constexpr Aesi(const Char(&literal)[arrayLength]) noexcept
C-style string literal constructor.
Definition Aesi.h:132
gpu constexpr friend auto operator*=(Aesi &multiplication, const Aesi &factor) noexcept -> Aesi &
Multiplication assignment operator.
Definition Aesi.h:469
gpu constexpr Aesi() noexcept=default
Default constructor.
gpu constexpr auto operator+() const noexcept -> Aesi
Unary plus operator.
Definition Aesi.h:220
gpu constexpr auto bitCount() const noexcept -> std::size_t
Get amount of non-empty bits in number right to left.
Definition Aesi.h:870
gpu constexpr friend auto operator==(const Aesi &our, const Aesi &other) noexcept -> bool=default
Equality operator.
Long precision unsigned integer.
Definition Aeu.h:83
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 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
static gpu constexpr auto power2(std::size_t power) noexcept -> Aeu
Fast exponentiation for powers of 2.
Definition Aeu.h:1267
gpu constexpr auto isEven() const noexcept -> bool
Check whether number is even.
Definition Aeu.h:1053
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 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 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 auto isOdd() const noexcept -> bool
Check whether number is odd.
Definition Aeu.h:1046
gpu constexpr auto swap(Aeu &other) noexcept -> void
Make swap between two objects.
Definition Aeu.h:1091
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
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 getBit(std::size_t index) const noexcept -> bool
Get bit in number by index staring from the right.
Definition Aeu.h:934
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