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 inline 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 inline 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 constexpr Aesi() noexcept = default;
83
87 constexpr ~Aesi() noexcept = default;
88
93 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 base = Base(static_cast<unsigned long long>(-value));
104 sign = Negative;
105 } else if(value > 0) {
106 base = Base(static_cast<unsigned long long>(value));
107 sign = Positive;
108 } else {
109 base = {};
110 sign = Zero;
111 }
112 }
113
121 template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
122 gpu constexpr Aesi(const Char* ptr, std::size_t size) noexcept : base(ptr, size) {
123 if(!base.isZero())
124 sign = traverseDashes(ptr, size);
125 else sign = Sign::Zero;
126 }
127
132 template <typename Char, std::size_t arrayLength> requires (arrayLength > 1 && (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>))
133 gpu constexpr Aesi(const Char (&literal)[arrayLength]) noexcept : Aesi(literal, arrayLength) {}
134
139 template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
140 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
141 gpu constexpr Aesi(String&& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}
142
143 template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
144 std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
145 gpu constexpr Aesi(const String& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}
146
151 explicit gpu constexpr Aesi(const Aeu<bitness>& value) : sign(Sign::Positive), base(value) {}
152
153
154#ifdef AESI_GMP_INTEGRATION
159 constexpr Aesi(const mpz_class& number) {
160 using enum Sign;
161 if(number == 0) {
162 base = {};
163 sign = Zero;
164 } else {
165 base = number;
166 if(number < 0)
167 sign = Negative;
168 else sign = Positive;
169 }
170 }
171#endif
172
177 template <typename Integral> requires (std::is_signed_v<Integral>)
178 gpu constexpr Aesi& operator=(Integral value) noexcept {
179 return *this = Aesi(value);
180 }
181
186 constexpr Aesi& operator=(const Aesi& other) noexcept = default;
187 /* ----------------------------------------------------------------------- */
188
189
190 /* --------------------- @name Arithmetic operators. --------------------- */
191 /* ------------------------- @name Unary operators. -------------------------- */
197 gpu constexpr auto operator+() const noexcept -> Aesi { return *this; }
198
203 [[nodiscard]]
204 gpu constexpr auto operator-() const noexcept -> Aesi { Aesi copy = *this; copy.inverse(); return copy; }
205
210 gpu constexpr auto operator++() noexcept -> Aesi& {
211 using enum Sign;
212 if(sign == Negative) {
213 --base; if(base.isZero()) sign = Zero;
214 } else if(sign == Positive) {
215 ++base;
216 } else { base = 1u; sign = Positive; }
217 return *this;
218 }
219
224 gpu constexpr auto operator++(int) & noexcept -> Aesi { Aesi old = *this; operator++(); return old; }
225
230 gpu constexpr auto operator--() noexcept -> Aesi& {
231 using enum Sign;
232 if(sign == Negative) {
233 ++base;
234 } else if(sign == Positive) {
235 --base; if(base.isZero()) sign = Zero;
236 } else { base = 1u; sign = Negative; }
237 return *this;
238 }
239
244 gpu constexpr auto operator--(int) & noexcept -> Aesi { Aesi old = *this; operator--(); return old; }
245 /* --------------------------------------------------------------------------- */
246
247 /* ------------------------ @name Addition operators. ------------------------ */
254 [[nodiscard]]
255 gpu constexpr friend auto operator+(const Aesi& addition, const Aesi& addendum) noexcept -> Aesi {
256 Aesi result = addition; result += addendum; return result;
257 }
258
265 gpu constexpr friend auto operator+=(Aesi& addition, const Aesi& addendum) noexcept -> Aesi& {
266 using enum Sign;
267 Sign& lSign = addition.sign; const Sign& rSign = addendum.sign;
268 Base& lBase = addition.base; const Base& rBase = addendum.base;
269
270 if(rSign == Zero)
271 return addition;
272 else if(lSign == Zero)
273 return addition = addendum;
274 else if(lSign == rSign) {
275 lBase += rBase;
276 return addition;
277 }
278
279 if(lSign == Positive) {
280 switch(lBase.compareTo(rBase)) {
281 using enum Comparison;
282 case greater: {
283 lBase -= rBase;
284 return addition;
285 }
286 case less: {
287 lBase = rBase - lBase;
288 lSign = Negative;
289 return addition;
290 }
291 default: {
292 lSign = Zero;
293 return addition;
294 }
295 }
296 } else {
297 switch(const auto ratio = lBase.compareTo(rBase)) {
298 using enum Comparison;
299 case greater: {
300 lBase -= rBase;
301 return addition;
302 }
303 case less: {
304 lBase = rBase - lBase;
305 lSign = Positive;
306 return addition;
307 }
308 default: {
309 lSign = Zero;
310 return addition;
311 }
312 }
313 }
314 }
315 /* --------------------------------------------------------------------------- */
316
317 /* ----------------------- @name Subtraction operators. ---------------------- */
324 [[nodiscard]]
325 gpu constexpr friend auto operator-(const Aesi& subtraction, const Aesi& subtrahend) noexcept -> Aesi {
326 Aesi result = subtraction; result -= subtrahend; return result;
327 }
328
335 gpu constexpr friend auto operator-=(Aesi& subtraction, const Aesi& subtrahend) noexcept -> Aesi& {
336 using enum Sign;
337 Sign& lSign = subtraction.sign; const Sign& rSign = subtrahend.sign;
338 Base& lBase = subtraction.base; const Base& rBase = subtrahend.base;
339
340 if(rSign == Zero)
341 return subtraction;
342 if(lSign == Zero) {
343 subtraction = subtrahend;
344 subtraction.inverse();
345 return subtraction;
346 }
347
348 if(lSign == Positive) {
349 if(rSign == Positive) {
350 switch(lBase.compareTo(rBase)) {
351 using enum Comparison;
352 case greater: {
353 lBase -= rBase;
354 return subtraction;
355 }
356 case less: {
357 lBase = rBase - lBase;
358 lSign = Negative;
359 return subtraction;
360 }
361 default: {
362 lSign = Zero;
363 return subtraction;
364 }
365 }
366 } else {
367 lBase += rBase;
368 return subtraction;
369 }
370 } else {
371 if(rSign == Negative) {
372 switch(lBase.compareTo(rBase)) {
373 using enum Comparison;
374 case greater: {
375 lBase -= rBase;
376 return subtraction;
377 }
378 case less: {
379 lBase = rBase - lBase;
380 lSign = Positive;
381 return subtraction;
382 }
383 default: {
384 lSign = Zero;
385 return subtraction;
386 }
387 }
388 } else {
389 lBase += rBase;
390 return subtraction;
391 }
392 }
393 }
394 /* --------------------------------------------------------------------------- */
395
396 /* --------------------- @name Multiplication operators. --------------------- */
403 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
404 gpu constexpr friend auto operator*(const Aesi& multiplication, Integral factor) noexcept -> Aesi {
405 Aesi result = multiplication; result *= factor; return result;
406 }
407
414 [[nodiscard]]
415 gpu constexpr friend auto operator*(const Aesi& multiplication, const Aesi& factor) noexcept -> Aesi {
416 Aesi result = multiplication; result *= factor; return result;
417 }
418
425 template <typename Integral> requires (std::is_integral_v<Integral>)
426 gpu constexpr friend auto operator*=(Aesi& multiplication, Integral factor) noexcept -> Aesi& {
427 using enum Sign;
428 if(factor == 0) {
429 multiplication.sign = Zero;
430 } else {
431 if(factor < 0) {
432 multiplication.inverse();
433 factor = static_cast<Integral>(-factor);
434 }
435 multiplication.base *= static_cast<unsigned long long>(factor);
436 }
437 return multiplication;
438 }
439
446 gpu constexpr friend auto operator*=(Aesi& multiplication, const Aesi& factor) noexcept -> Aesi& {
447 using enum Sign;
448 if(factor.isZero()) {
449 multiplication.sign = Zero;
450 } else {
451 if(factor.isNegative())
452 multiplication.inverse();
453 multiplication.base *= factor.base;
454 }
455 return multiplication;
456 }
457 /* --------------------------------------------------------------------------- */
458
459 /* ------------------------ @name Division operators. ------------------------ */
467 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
468 gpu constexpr friend auto operator/(const Aesi& division, Integral divisor) noexcept -> Aesi {
469 Aesi result = division; result /= divisor; return result;
470 }
471
479 [[nodiscard]]
480 gpu constexpr friend auto operator/(const Aesi& division, const Aesi& divisor) noexcept -> Aesi {
481 Aesi result = division; result /= divisor; return result;
482 }
483
491 template <typename Integral> requires (std::is_integral_v<Integral>)
492 gpu constexpr friend auto operator/=(Aesi& division, Integral divisor) noexcept -> Aesi& {
493 using enum Sign;
494 if(divisor == 0) {
495 division.sign = Zero;
496 } else {
497 if(divisor < 0) {
498 division.inverse();
499 divisor = static_cast<Integral>(-divisor);
500 }
501 division.base /= static_cast<unsigned long long>(divisor);
502 if(division.base.isZero()) division.sign = Zero;
503 }
504 return division;
505 }
506
514 gpu constexpr friend auto operator/=(Aesi& division, const Aesi& divisor) noexcept -> Aesi& {
515 using enum Sign;
516 if(divisor.isZero()) {
517 division.sign = Zero;
518 } else {
519 if(divisor.isNegative())
520 division.inverse();
521 division.base /= divisor.base;
522 if(division.base.isZero()) division.sign = Zero;
523 }
524 return division;
525 }
526 /* --------------------------------------------------------------------------- */
527
528 /* ------------------------- @name Modulo operators. ------------------------- */
536 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
537 gpu constexpr friend auto operator%(const Aesi& modulation, Integral modulo) noexcept -> Aesi {
538 Aesi result = modulation; result %= modulo; return result;
539 }
540
549 [[nodiscard]]
550 gpu constexpr friend auto operator%(const Aesi& modulation, const Aesi& modulo) noexcept -> Aesi {
551 Aesi result = modulation; result %= modulo; return result;
552 }
553
561 template <typename Integral> requires (std::is_integral_v<Integral>)
562 gpu constexpr friend auto operator%=(Aesi& modulation, Integral modulo) noexcept -> Aesi& {
563 using enum Sign;
564 if(modulo == 0) {
565 modulation.sign = Zero;
566 } else {
567 if(modulo < 0) {
568 modulation.inverse();
569 modulo = static_cast<Integral>(-modulo);
570 }
571 modulation.base %= static_cast<unsigned long long>(modulo);
572 }
573 return modulation;
574 }
575
584 gpu constexpr friend auto operator%=(Aesi& modulation, const Aesi& modulo) noexcept -> Aesi& {
585 if(modulo.isZero())
586 return modulation;
587
588 if(modulo.isNegative())
589 modulation.inverse();
590 modulation.base %= modulo.base;
591 if(modulation.base.isZero())
592 modulation.sign = Sign::Zero;
593
594 return modulation;
595 }
596 /* --------------------------------------------------------------------------- */
597 /* ----------------------------------------------------------------------- */
598
599 /* --------------------- @name Comparison operators. --------------------- */
600 /* ------------------------ @name Equality operators. ------------------------ */
607 template <typename Integral> requires (std::is_integral_v<Integral>)
608 gpu constexpr friend auto operator==(const Aesi& our, Integral integral) noexcept -> bool {
609 return our.compareTo(integral) == Comparison::equal;
610 }
611
618 template <std::size_t otherBitness>
619 gpu constexpr friend auto operator==(const Aesi& our, const Aesi<otherBitness>& other) noexcept -> bool {
620 if constexpr (bitness == otherBitness) {
621 return our.compareTo(other) == Comparison::equal;
622 } else {
623 return our.precisionCast<otherBitness>() == other;
624 }
625 }
626
627#ifdef AESI_GMP_INTEGRATION
634 template <typename T, typename U>
635 constexpr friend auto operator==(const Aesi& our, const __gmp_expr<T, U>& other) noexcept -> bool {
636 return our == Aesi(mpz_class(other));
637 }
638#endif
639 /* --------------------------------------------------------------------------- */
640
641
642 /* ----------------------- @name Comparison operators. ----------------------- */
648 template <typename Integral> requires (std::is_integral_v<Integral>)
649 gpu constexpr auto compareTo(Integral integral) const noexcept -> Comparison {
650 using enum Sign; using enum Comparison;
651 if(integral == 0) {
652 switch(sign) {
653 case Positive:
654 return greater;
655 case Negative:
656 return less;
657 default:
658 return equal;
659 }
660 } else if(integral < 0) {
661 if(sign == Negative)
662 switch(base.compareTo(static_cast<uint64_t>(-static_cast<int64_t>(integral)))) {
663 using enum Comparison;
664 case greater:
665 return less;
666 case less:
667 return greater;
668 default:
669 return equal;
670 }
671 else return greater;
672 } else {
673 if(sign == Positive)
674 return base.compareTo(static_cast<uint64_t>(static_cast<int64_t>(integral)));
675 return less;
676 }
677 }
678
684 template <std::size_t otherBitness = bitness> [[nodiscard]]
685 gpu constexpr auto compareTo(const Aesi<otherBitness>& value) const noexcept -> Comparison {
686 return precisionCast<otherBitness>().compareTo(value);
687 }
688
694 [[nodiscard]]
695 gpu constexpr auto compareTo(const Aesi& value) const noexcept -> Comparison {
696 using enum Sign; using enum Comparison;
697 if(value.isZero()) {
698 switch(sign) {
699 case Positive:
700 return greater;
701 case Negative:
702 return less;
703 default:
704 return equal;
705 }
706 }
707
708 if(value.isNegative()) {
709 if(sign == Negative)
710 switch(base.compareTo(value.base)) {
711 case greater:
712 return less;
713 case less:
714 return greater;
715 default:
716 return equal;
717 }
718 return greater;
719 }
720
721 if(sign == Positive)
722 return base.compareTo(value.base);
723 return less;
724 }
725 /* --------------------------------------------------------------------------- */
726
727 /* ------------------------ @name Spaceship operators. ----------------------- */
728#if (defined(__CUDACC__) || __cplusplus < 202002L || defined (PRE_CPP_20)) && !defined DOXYGEN_SKIP
732 gpu constexpr auto operator!=(const Aeu<bitness>& value) const noexcept -> bool {
733 return !this->operator==(value);
734 }
735 gpu constexpr auto operator<(const Aeu<bitness>& value) const noexcept -> bool {
736 return this->compareTo(value) == Comparison::less;
737 }
738 gpu constexpr auto operator<=(const Aeu<bitness>& value) const noexcept -> bool {
739 return !this->operator>(value);
740 }
741 gpu constexpr auto operator>(const Aeu<bitness>& value) const noexcept -> bool {
742 return this->compareTo(value) == Comparison::greater;
743 }
744 gpu constexpr auto operator>=(const Aeu<bitness>& value) const noexcept -> bool {
745 return !this->operator<(value);
746 }
747#else
754 gpu constexpr auto operator<=>(const Aesi& other) const noexcept -> std::strong_ordering {
755 switch(this->compareTo(other)) {
756 using enum Comparison;
757 case less:
758 return std::strong_ordering::less;
759 case greater:
760 return std::strong_ordering::greater;
761 case equal:
762 return std::strong_ordering::equal;
763 default:
764 return std::strong_ordering::equivalent;
765 }
766 }
767
774 template <typename Object>
775 gpu constexpr auto operator<=>(const Object& other) const noexcept -> std::strong_ordering {
776 switch(this->compareTo(other)) {
777 using enum Comparison;
778 case less:
779 return std::strong_ordering::less;
780 case greater:
781 return std::strong_ordering::greater;
782 case equal:
783 return std::strong_ordering::equal;
784 default:
785 return std::strong_ordering::equivalent;
786 }
787 }
788#endif
789 /* --------------------------------------------------------------------------- */
790 /* ----------------------------------------------------------------------- */
791
792 /* ---------------------- @name Supporting methods. ---------------------- */
799 gpu constexpr auto setBit(std::size_t index, bool bit) noexcept -> void { return base.setBit(index, bit); }
800
807 [[nodiscard]]
808 gpu constexpr auto getBit(std::size_t index) const noexcept -> bool { return base.getBit(index); }
809
816 gpu constexpr auto setByte(std::size_t index, byte byte) noexcept -> void { return base.setByte(index, byte); }
817
824 [[nodiscard]]
825 gpu constexpr auto getByte(std::size_t index) const noexcept -> byte { return base.getByte(index); }
826
833 gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void { return base.setBlock(index, block); }
834
841 [[nodiscard]]
842 gpu constexpr auto getBlock(std::size_t index) const noexcept -> block { return base.getBlock(index); }
843
848 [[nodiscard]]
849 gpu constexpr auto byteCount() const noexcept -> std::size_t { return base.byteCount(); }
850
855 [[nodiscard]]
856 gpu constexpr auto bitCount() const noexcept -> std::size_t { return base.bitCount(); }
857
862 [[nodiscard]]
863 gpu constexpr auto isOdd() const noexcept -> bool { return base.isOdd(); }
864
869 [[nodiscard]]
870 gpu constexpr auto isEven() const noexcept -> bool { return base.isEven(); }
871
876 [[nodiscard]]
877 gpu constexpr auto isZero() const noexcept -> bool { return sign == Sign::Zero; }
878
883 [[nodiscard]]
884 gpu constexpr auto isPositive() const noexcept -> bool { return sign == Sign::Positive; }
885
890 [[nodiscard]]
891 gpu constexpr auto isNegative() const noexcept -> bool { return sign == Sign::Negative; }
892
897 [[nodiscard]]
898 gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t { return base.filledBlocksNumber(); }
899
904 [[nodiscard]]
905 gpu static constexpr auto getBitness() noexcept -> std::size_t { return bitness; }
906
911 [[nodiscard]]
912 gpu static constexpr auto totalBlocksNumber() noexcept -> std::size_t { return Aeu<bitness>::totalBlocksNumber(); }
913
918 gpu constexpr auto swap(Aesi& other) noexcept -> void {
919 Sign tSign = sign; sign = other.sign; other.sign = tSign;
920 base.swap(other.base);
921 }
922
927 gpu constexpr auto inverse() noexcept -> void {
928 using enum Sign;
929 sign = (sign == Zero ? Zero : (sign == Negative ? Positive : Negative));
930 }
931 /* ----------------------------------------------------------------------- */
932
933 /* -------------- @name Public arithmetic and number theory. ------------- */
942 gpu static constexpr auto divide(const Aesi& number, const Aesi& divisor, Aesi& quotient, Aesi& remainder) noexcept -> void {
943 using enum Sign;
944 if(number.sign == Zero || divisor.sign == Zero) {
945 quotient.sign = Zero;
946 remainder.sign = Zero;
947 return;
948 }
949
950 Base::divide(number.base, divisor.base, quotient.base, remainder.base);
951 if(number.sign == Positive) {
952 if(divisor.sign == Positive) {
953 quotient.sign = Positive;
954 remainder.sign = Positive;
955 } else {
956 quotient.sign = Negative;
957 remainder.sign = Positive;
958 }
959 } else {
960 if(divisor.sign == Positive) {
961 quotient.sign = Negative;
962 remainder.sign = Negative;
963 } else {
964 quotient.sign = Positive;
965 remainder.sign = Negative;
966 }
967 }
968
969 if(quotient.base.isZero())
970 quotient.sign = Zero;
971 if(remainder.base.isZero())
972 remainder.sign = Zero;
973 }
974
980 [[nodiscard]]
981 gpu constexpr auto squareRoot() const noexcept -> Aesi {
982 using enum Sign;
983 if(sign == Positive)
984 return Aesi { Positive, base.squareRoot() };
985 return Aesi { 0 };
986 }
987
992 [[nodiscard]]
993 gpu static constexpr auto power2(std::size_t power) noexcept -> Aesi {
994 using enum Sign;
995 Aesi result { Positive, Aeu<bitness>::power2(power) };
996 if(result.base.isZero())
997 result.sign = Zero;
998 return result;
999 }
1000 /* ----------------------------------------------------------------------- */
1001
1006 template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
1007 gpu constexpr auto integralCast() const noexcept -> Integral {
1008 using enum Sign;
1009 if(sign == Zero)
1010 return Integral(0);
1011
1012 if constexpr (std::is_signed_v<Integral>) {
1013 if(sign == Negative)
1014 return base.template integralCast<Integral>() * -1;
1015 }
1016
1017 return base.template integralCast<Integral>();
1018 }
1019
1024 template <std::size_t newBitness> requires (newBitness != bitness) [[nodiscard]]
1025 gpu constexpr auto precisionCast() const noexcept -> Aesi<newBitness> {
1026 using enum Sign;
1027 if(sign != Zero) {
1028 Aesi<newBitness> result = 1;
1029
1030 const std::size_t blockBoarder = (newBitness > bitness ? totalBlocksNumber() : Aesi<newBitness>::totalBlocksNumber());
1031 for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
1032 result.setBlock(blockIdx, getBlock(blockIdx));
1033
1034 if(sign == Negative)
1035 result.inverse();
1036
1037 return result;
1038 }
1039
1040 return Aesi<newBitness> {};
1041 }
1042
1047 gpu constexpr auto unsignedCast() const noexcept -> Aeu<bitness> { return base; }
1048
1049 /* ----------------- @name Public input-output operators. ---------------- */
1060 template <byte notation, bool hexUppercase = false, typename Char> requires (std::is_same_v<Char, char> || (std::is_same_v<Char, wchar_t> && (notation == 2 || notation == 8 || notation == 10 || notation == 16)))
1061 gpu constexpr auto getString(Char* buffer, std::size_t bufferSize, bool showBase = false) const noexcept -> std::size_t {
1062 using enum Sign;
1063
1064 if(sign != Zero) {
1065 if(sign == Negative && bufferSize > 0) {
1066 *buffer++ = [] { if constexpr (std::is_same_v<Char, char>) { return '-'; } else { return L'-'; } } ();
1067 --bufferSize;
1068 }
1069 return base.template getString<notation, hexUppercase, Char>(buffer, bufferSize, showBase);
1070 }
1071
1072 if(showBase) {
1073 switch(notation) {
1074 case 2: {
1075 if(bufferSize < 3) return 0;
1076 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1077 buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'b'; } else { return L'b'; } } ();
1078 buffer[2] = buffer[0];
1079 return 3;
1080 }
1081 case 8: {
1082 if(bufferSize < 3) return 0;
1083 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1084 buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'o'; } else { return L'o'; } } ();
1085 buffer[2] = buffer[0];
1086 return 3;
1087 }
1088 case 16: {
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 'x'; } else { return L'x'; } } ();
1092 buffer[2] = buffer[0];
1093 return 3;
1094 }
1095 default: {
1096 if(bufferSize < 1) return 0;
1097 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1098 return 1;
1099 }
1100 }
1101 }
1102
1103 buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1104 return 1;
1105 }
1106
1118 template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1119 friend constexpr auto operator<<(std::basic_ostream<Char>& os, const Aesi& number) -> std::basic_ostream<Char>& {
1120 using enum Sign;
1121 if(number.sign != Zero) {
1122 if(number.sign == Negative)
1123 os << [] { if constexpr (std::is_same_v<Char, char>) { return '-'; } else { return L'-'; } } ();
1124 return os << number.base;
1125 }
1126 return os << '0';
1127 }
1128 /* ----------------------------------------------------------------------- */
1129
1130#if defined __CUDACC__ || defined DOXYGEN_SKIP
1137 __device__ constexpr auto tryAtomicSet(const Aesi& value) noexcept -> void {
1138 base.tryAtomicSet(value.base);
1139 sign = value.sign; /* TODO: Make enum substitution using existing CUDA atomics */
1140 }
1141
1148 __device__ constexpr auto tryAtomicExchange(const Aesi& value) noexcept -> void {
1149 base.tryAtomicExchange(value.base);
1150 sign = value.sign; /* TODO: Make enum substitution using existing CUDA atomics */
1151 }
1152#endif
1153};
1154
1155/* -------------------------------------------- @name Type-definitions ------------------------------------------- */
1160
1165
1170
1175
1180
1185
1190
1195
1200
1205
1210/* ---------------------------------------------------------------------------------------------------------------- */
1211
1212/* ------------------------------------------ @name Integral conversions ----------------------------------------- */
1219template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1220gpu constexpr auto operator+(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) + value; }
1221
1228template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1229gpu constexpr auto operator-(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) - value; }
1230
1237template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1238gpu constexpr auto operator*(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) * value; }
1239
1246template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1247gpu constexpr auto operator/(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) / value; }
1248
1255template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1256gpu constexpr auto operator%(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) % value; }
1257
1264template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1265gpu constexpr auto operator^(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) ^ value; }
1266
1273template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1274gpu constexpr auto operator&(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) & value; }
1275
1282template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1283gpu constexpr auto operator|(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) | value; }
1284/* ---------------------------------------------------------------------------------------------------------------- */
1285
1286#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:550
gpu constexpr auto byteCount() const noexcept -> std::size_t
Get amount of non-empty bytes in number right to left.
Definition Aesi.h:849
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:775
gpu constexpr friend auto operator/=(Aesi &division, const Aesi &divisor) noexcept -> Aesi &
Assignment division operator.
Definition Aesi.h:514
gpu constexpr auto swap(Aesi &other) noexcept -> void
Make swap between two objects.
Definition Aesi.h:918
gpu constexpr auto inverse() noexcept -> void
Invertes number's bitness.
Definition Aesi.h:927
gpu constexpr Aesi(const Aeu< bitness > &value)
Unsigned integer conversion.
Definition Aesi.h:151
gpu constexpr auto operator++(int) &noexcept -> Aesi
Postfix increment operator.
Definition Aesi.h:224
gpu constexpr auto operator--(int) &noexcept -> Aesi
Postfix decrement operator.
Definition Aesi.h:244
gpu constexpr friend auto operator-=(Aesi &subtraction, const Aesi &subtrahend) noexcept -> Aesi &
Subtraction assignment operator.
Definition Aesi.h:335
gpu constexpr auto operator--() noexcept -> Aesi &
Prefix decrement operator.
Definition Aesi.h:230
gpu constexpr auto compareTo(const Aesi< otherBitness > &value) const noexcept -> Comparison
Different precision comparison operator.
Definition Aesi.h:685
gpu constexpr friend auto operator==(const Aesi &our, const Aesi< otherBitness > &other) noexcept -> bool
Different precision equlity operator.
Definition Aesi.h:619
__device__ constexpr auto tryAtomicSet(const Aesi &value) noexcept -> void
Atomicity-oriented object assignment operator.
Definition Aesi.h:1137
gpu constexpr friend auto operator*(const Aesi &multiplication, const Aesi &factor) noexcept -> Aesi
Multiplication operator.
Definition Aesi.h:415
gpu constexpr auto operator++() noexcept -> Aesi &
Prefix increment operator.
Definition Aesi.h:210
constexpr Aesi & operator=(const Aesi &other) noexcept=default
Copy assignment operator.
gpu constexpr friend auto operator%=(Aesi &modulation, const Aesi &modulo) noexcept -> Aesi &
Modulo assignment operator.
Definition Aesi.h:584
gpu constexpr auto operator<=>(const Aesi &other) const noexcept -> std::strong_ordering
Three-way comparison operator.
Definition Aesi.h:754
gpu constexpr Aesi(String &&stringView) noexcept
String / String-view constructor.
Definition Aesi.h:141
gpu constexpr friend auto operator+(const Aesi &addition, const Aesi &addendum) noexcept -> Aesi
Addition operator.
Definition Aesi.h:255
static gpu constexpr auto power2(std::size_t power) noexcept -> Aesi
Fast exponentiation of 2.
Definition Aesi.h:993
gpu constexpr auto integralCast() const noexcept -> Integral
Cast for built-in integral types.
Definition Aesi.h:1007
gpu constexpr auto precisionCast() const noexcept -> Aesi< newBitness >
Number's precision cast.
Definition Aesi.h:1025
gpu constexpr friend auto operator+=(Aesi &addition, const Aesi &addendum) noexcept -> Aesi &
Addition assignment operator.
Definition Aesi.h:265
gpu constexpr friend auto operator-(const Aesi &subtraction, const Aesi &subtrahend) noexcept -> Aesi
Subtraction operator.
Definition Aesi.h:325
gpu constexpr friend auto operator/(const Aesi &division, const Aesi &divisor) noexcept -> Aesi
Division operator.
Definition Aesi.h:480
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:833
gpu constexpr auto isOdd() const noexcept -> bool
Check whether number is odd.
Definition Aesi.h:863
static gpu constexpr auto getBitness() noexcept -> std::size_t
Get number's precision.
Definition Aesi.h:905
__device__ constexpr auto tryAtomicExchange(const Aesi &value) noexcept -> void
Atomicity-oriented object exchangement operator.
Definition Aesi.h:1148
gpu constexpr auto getBlock(std::size_t index) const noexcept -> block
Get block in number by index starting from the right.
Definition Aesi.h:842
gpu constexpr Aesi(const Char *ptr, std::size_t size) noexcept
Pointer-based character constructor.
Definition Aesi.h:122
gpu constexpr auto isNegative() const noexcept -> bool
Check whether number is negative.
Definition Aesi.h:891
constexpr Aesi() noexcept=default
Default constructor.
gpu constexpr auto isEven() const noexcept -> bool
Check whether number is even.
Definition Aesi.h:870
gpu constexpr auto isZero() const noexcept -> bool
Check whether number is zero.
Definition Aesi.h:877
gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t
Get number of non-empty blocks inside object starting from the right.
Definition Aesi.h:898
gpu constexpr auto getByte(std::size_t index) const noexcept -> byte
Get byte in number by index starting from the right.
Definition Aesi.h:825
gpu constexpr auto operator-() const noexcept -> Aesi
Unary minus operator.
Definition Aesi.h:204
gpu constexpr auto getBit(std::size_t index) const noexcept -> bool
Get bit in number by index starting from the right.
Definition Aesi.h:808
gpu constexpr auto squareRoot() const noexcept -> Aesi
Square root.
Definition Aesi.h:981
gpu constexpr auto compareTo(const Aesi &value) const noexcept -> Comparison
Comparison operator.
Definition Aesi.h:695
gpu constexpr auto compareTo(Integral integral) const noexcept -> Comparison
Comparison operator for built-in types.
Definition Aesi.h:649
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:816
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:912
gpu constexpr auto isPositive() const noexcept -> bool
Check whether number is positive.
Definition Aesi.h:884
static gpu constexpr auto divide(const Aesi &number, const Aesi &divisor, Aesi &quotient, Aesi &remainder) noexcept -> void
Integral division.
Definition Aesi.h:942
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:799
gpu constexpr auto unsignedCast() const noexcept -> Aeu< bitness >
Unsigned cast.
Definition Aesi.h:1047
gpu constexpr Aesi(const Char(&literal)[arrayLength]) noexcept
C-style string literal constructor.
Definition Aesi.h:133
gpu constexpr friend auto operator*=(Aesi &multiplication, const Aesi &factor) noexcept -> Aesi &
Multiplication assignment operator.
Definition Aesi.h:446
gpu constexpr auto getString(Char *buffer, std::size_t bufferSize, bool showBase=false) const noexcept -> std::size_t
Character buffer output operator.
Definition Aesi.h:1061
gpu constexpr auto operator+() const noexcept -> Aesi
Unary plus operator.
Definition Aesi.h:197
gpu constexpr auto bitCount() const noexcept -> std::size_t
Get amount of non-empty bits in number right to left.
Definition Aesi.h:856
Long precision unsigned integer.
Definition Aeu.h:84
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 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
static gpu constexpr auto power2(std::size_t power) noexcept -> Aeu
Fast exponentiation for powers of 2.
Definition Aeu.h:1248
gpu constexpr auto isEven() const noexcept -> bool
Check whether number is even.
Definition Aeu.h:1034
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 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 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 auto isOdd() const noexcept -> bool
Check whether number is odd.
Definition Aeu.h:1027
gpu constexpr auto swap(Aeu &other) noexcept -> void
Make swap between two objects.
Definition Aeu.h:1072
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
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 getBit(std::size_t index) const noexcept -> bool
Get bit in number by index staring from the right.
Definition Aeu.h:915
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