Aesi Multiprecision
C++ class library of long integer arithmetic for GPU parallelization
Aesi.h
Go to the documentation of this file.
1 #ifndef AESI_MULTIPRECISION
2 #define AESI_MULTIPRECISION
3 
5 #include "Aeu.h"
7 
13 namespace {
14  enum class Sign { Zero = 0, Positive = 1, Negative = -1 };
15 }
16 
22 template <std::size_t bitness = 512> requires (bitness % blockBitLength == 0)
23 class Aesi final {
24  /* -------------------------- @name Class members. ----------------------- */
25  Sign sign;
26 
27  using Base = Aeu<bitness>;
28  Base base;
29  /* ----------------------------------------------------------------------- */
30 
31  gpu constexpr Aesi(Sign withSign, Base withBase): sign { withSign }, base { withBase } {};
32 
33 public:
34  /* --------------------- @name Different constructors. ------------------- */
38  gpu constexpr Aesi() noexcept = default;
39 
44  gpu constexpr Aesi(const Aesi& copy) noexcept = default;
45 
50  template <typename Integral> requires (std::is_integral_v<Integral>)
51  gpu constexpr Aesi(Integral value) noexcept {
52  if(value < 0) {
53  value *= -1;
54  base = Base(static_cast<unsigned long long>(value));
55  sign = Sign::Negative;
56  } else if(value > 0) {
57  base = Base(static_cast<unsigned long long>(value));
58  sign = Sign::Positive;
59  } else
60  sign = Sign::Zero;
61  }
62 
70  template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
71  gpu constexpr Aesi(const Char* ptr, std::size_t size) noexcept : base(ptr, size) {
72  if(!base.isZero()) {
73  uint8_t positive = 1;
74 
75  const auto dash = [] {
76  if constexpr (std::is_same_v<Char, char>) {
77  return '-';
78  } else {
79  return L'-';
80  }
81  } ();
82  for(std::size_t i = 0; i < size; ++i)
83  if(ptr[i] == dash) positive ^= 1;
84 
85  sign = (positive ? Sign::Positive : Sign::Negative);
86  } else sign = Sign::Zero;
87  }
88 
93  template <typename Char, std::size_t arrayLength> requires (arrayLength > 1 && (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>))
94  gpu constexpr Aesi(const Char (&literal)[arrayLength]) noexcept : Aesi(literal, arrayLength) {}
95 
100  template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
101  std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
102  gpu constexpr Aesi(String&& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}
103 
104  template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
105  std::decay_t<String>> || std::is_same_v<std::basic_string_view<Char>, std::decay_t<String>>)
106  gpu constexpr Aesi(const String& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}
107 
112  explicit gpu constexpr Aesi(const Aeu<bitness>& value) : sign(Sign::Positive), base(value) {}
113 
114 #ifdef AESI_CRYPTOPP_INTEGRATION
119  constexpr Aesi(const CryptoPP::Integer& number) {
120  if(number.IsZero())
121  sign = Sign::Zero;
122  else {
123  base = number;
124  if(number.IsNegative())
125  sign = Sign::Negative;
126  else sign = Sign::Positive;
127  }
128  }
129 #endif
130 
131 #ifdef AESI_GMP_INTEGRATION
136  constexpr Aesi(const mpz_class& number) {
137  if(number == 0)
138  sign = Sign::Zero;
139  else {
140  base = number;
141  if(number < 0)
142  sign = Sign::Negative;
143  else sign = Sign::Positive;
144  }
145  }
146 #endif
147 
152  template <typename Integral> requires (std::is_signed_v<Integral>)
153  gpu constexpr Aesi& operator=(Integral value) noexcept {
154  if(value != 0) {
155  if(value < 0) {
156  sign = Sign::Negative;
157  value *= -1;
158  } else sign = Sign::Positive;
159  base = static_cast<unsigned long long>(value);
160  } else sign = Sign::Zero;
161  return *this;
162  }
163 
168  gpu constexpr Aesi& operator=(const Aesi& other) noexcept { base = other.base; sign = other.sign; return *this; }
169  /* ----------------------------------------------------------------------- */
170 
171 
172  /* --------------------- @name Arithmetic operators. --------------------- */
173  /* ------------------------- @name Unary operators. -------------------------- */
179  gpu constexpr auto operator+() const noexcept -> Aesi { return *this; }
180 
185  [[nodiscard]]
186  gpu constexpr auto operator-() const noexcept -> Aesi { Aesi copy = *this; copy.inverse(); return copy; }
187 
192  gpu constexpr auto operator++() noexcept -> Aesi& {
193  if(sign == Sign::Negative) {
194  --base; if(base.isZero()) sign = Sign::Zero;
195  } else if(sign == Sign::Positive) {
196  ++base;
197  } else { base = 1u; sign = Sign::Positive; }
198  return *this;
199  }
200 
205  gpu constexpr auto operator++(int) & noexcept -> Aesi { Aesi old = *this; operator++(); return old; }
206 
211  gpu constexpr auto operator--() noexcept -> Aesi& {
212  if(sign == Sign::Negative) {
213  ++base;
214  } else if(sign == Sign::Positive) {
215  --base; if(base.isZero()) sign = Sign::Zero;
216  } else { base = 1u; sign = Sign::Negative; }
217  return *this;
218  }
219 
224  gpu constexpr auto operator--(int) & noexcept -> Aesi { Aesi old = *this; operator--(); return old; }
225  /* --------------------------------------------------------------------------- */
226 
227  /* ------------------------ @name Addition operators. ------------------------ */
233  [[nodiscard]]
234  gpu constexpr auto operator+(const Aesi& addendum) const noexcept -> Aesi { Aesi result = *this; result += addendum; return result; }
235 
241  gpu constexpr auto operator+=(const Aesi& addendum) noexcept -> Aesi& {
242  if(addendum.sign == Sign::Zero) /* Any += Zero; */
243  return *this;
244  if(sign == Sign::Zero) /* Zero += Any; */
245  return this->operator=(addendum);
246 
247  if(sign == addendum.sign) { /* Positive += Positive; */
248  base += addendum.base;
249  return *this;
250  }
251 
252  if(sign == Sign::Positive) { /* Positive += Negative; */
253  switch(base.compareTo(addendum.base)) {
254  case Comparison::greater: {
255  base -= addendum.base;
256  return *this;
257  }
258  case Comparison::less: {
259  base = addendum.base - base;
260  sign = Sign::Negative;
261  return *this;
262  }
263  default: {
264  sign = Sign::Zero;
265  return *this;
266  }
267  }
268  } else { /* Negative += Positive; */
269  switch(const auto ratio = base.compareTo(addendum.base)) {
270  case Comparison::greater: {
271  base -= addendum.base;
272  return *this;
273  }
274  case Comparison::less: {
275  base = addendum.base - base;
276  sign = Sign::Positive;
277  return *this;
278  }
279  default: {
280  sign = Sign::Zero;
281  return *this;
282  }
283  }
284  }
285  }
286  /* --------------------------------------------------------------------------- */
287 
288  /* ----------------------- @name Subtraction operators. ---------------------- */
294  [[nodiscard]]
295  gpu constexpr auto operator-(const Aesi& subtrahend) const noexcept -> Aesi { Aesi result = *this; result -= subtrahend; return result; }
296 
302  gpu constexpr auto operator-=(const Aesi& subtrahend) noexcept -> Aesi& {
303  if(subtrahend.sign == Sign::Zero) /* Any -= Zero; */
304  return *this;
305  if(sign == Sign::Zero) { /* Zero -= Any; */
306  *this = subtrahend;
307  this->inverse();
308  return *this;
309  }
310 
311  if(sign == Sign::Positive) {
312  if(subtrahend.sign == Sign::Positive) { /* Positive -= Positive; */
313  switch(base.compareTo(subtrahend.base)) {
314  case Comparison::greater: {
315  base -= subtrahend.base;
316  return *this;
317  }
318  case Comparison::less: {
319  base = subtrahend.base - base;
320  sign = Sign::Negative;
321  return *this;
322  }
323  default: {
324  sign = Sign::Zero;
325  return *this;
326  }
327  }
328  } else { /* Positive -= Negative; */
329  base += subtrahend.base;
330  return *this;
331  }
332  } else {
333  if(subtrahend.sign == Sign::Negative) { /* Negative -= Negative; */
334  switch(base.compareTo(subtrahend.base)) {
335  case Comparison::greater: {
336  base -= subtrahend.base;
337  return *this;
338  }
339  case Comparison::less: {
340  base = subtrahend.base - base;
341  sign = Sign::Positive;
342  return *this;
343  }
344  default: {
345  sign = Sign::Zero;
346  return *this;
347  }
348  }
349  } else { /* Negative -= Positive; */
350  base += subtrahend.base;
351  return *this;
352  }
353  }
354  }
355  /* --------------------------------------------------------------------------- */
356 
357  /* --------------------- @name Multiplication operators. --------------------- */
363  template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
364  gpu constexpr auto operator*(Integral factor) const noexcept -> Aesi { Aesi result = *this; result *= factor; return result; }
365 
371  [[nodiscard]]
372  gpu constexpr auto operator*(const Aesi& factor) const noexcept -> Aesi { Aesi result = *this; result *= factor; return result; }
373 
379  template <typename Integral> requires (std::is_integral_v<Integral>)
380  gpu constexpr auto operator*=(Integral factor) noexcept -> Aesi& {
381  if(factor == 0) {
382  sign = Sign::Zero;
383  } else {
384  if(factor < 0) {
385  this->inverse();
386  factor *= -1;
387  }
388  base.operator*=(static_cast<unsigned long long>(factor));
389  }
390  return *this;
391  }
392 
398  gpu constexpr auto operator*=(const Aesi& factor) noexcept -> Aesi& {
399  if(factor.isZero()) {
400  sign = Sign::Zero;
401  } else {
402  if(factor.isNegative())
403  this->inverse();
404  base.operator*=(factor.base);
405  }
406  return *this;
407  }
408  /* --------------------------------------------------------------------------- */
409 
410  /* ------------------------ @name Division operators. ------------------------ */
417  template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
418  gpu constexpr auto operator/(Integral divisor) const noexcept -> Aesi { Aesi result = *this; result /= divisor; return result; }
419 
426  [[nodiscard]]
427  gpu constexpr auto operator/(const Aesi& divisor) const noexcept -> Aesi { Aesi result = *this; result /= divisor; return result; }
428 
435  template <typename Integral> requires (std::is_integral_v<Integral>)
436  gpu constexpr auto operator/=(Integral divisor) noexcept -> Aesi& {
437  if(divisor == 0) {
438  sign = Sign::Zero;
439  } else {
440  if(divisor < 0) {
441  this->inverse();
442  divisor *= -1;
443  }
444  base.operator/=(static_cast<unsigned long long>(divisor));
445  if(base.isZero()) sign = Sign::Zero;
446  }
447  return *this;
448  }
449 
456  gpu constexpr auto operator/=(const Aesi& divisor) noexcept -> Aesi& {
457  if(divisor.isZero()) {
458  sign = Sign::Zero;
459  } else {
460  if(divisor.isNegative())
461  this->inverse();
462  base.operator/=(divisor.base);
463  if(base.isZero()) sign = Sign::Zero;
464  }
465  return *this;
466  }
467  /* --------------------------------------------------------------------------- */
468 
469  /* ------------------------- @name Modulo operators. ------------------------- */
476  template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
477  gpu constexpr auto operator%(Integral modulo) const noexcept -> Aesi { Aesi result = *this; result %= modulo; return result; }
478 
486  [[nodiscard]]
487  gpu constexpr auto operator%(const Aesi& modulo) const noexcept -> Aesi { Aesi result = *this; result %= modulo; return result; }
488 
495  template <typename Integral> requires (std::is_integral_v<Integral>)
496  gpu constexpr auto operator%=(Integral modulo) noexcept -> Aesi& {
497  if(modulo == 0) {
498  sign = Sign::Zero;
499  } else {
500  if(modulo < 0) {
501  this->inverse();
502  modulo *= -1;
503  }
504  base.operator%=(static_cast<unsigned long long>(modulo));
505  }
506  return *this;
507  }
508 
516  gpu constexpr auto operator%=(const Aesi& modulo) noexcept -> Aesi& {
517  if(modulo.isZero())
518  return *this;
519 
520  if(modulo.isNegative())
521  this->inverse();
522  base.operator%=(modulo.base);
523  if(base.isZero())
524  sign = Sign::Zero;
525 
526  return *this;
527  }
528  /* --------------------------------------------------------------------------- */
529  /* ----------------------------------------------------------------------- */
530 
531  /* --------------------- @name Comparison operators. --------------------- */
532  /* ------------------------ @name Equality operators. ------------------------ */
538  template <typename Integral> requires (std::is_integral_v<Integral>)
539  gpu constexpr auto operator==(Integral integral) const noexcept -> bool {
540  return compareTo(integral) == Comparison::equal;
541  }
542 
548  gpu constexpr auto operator==(const Aesi& other) const noexcept -> bool {
549  return sign == other.sign && base == other.base;
550  }
551 
557  template <std::size_t otherBitness> requires (otherBitness != bitness)
558  gpu constexpr auto operator==(const Aesi<otherBitness>& other) const noexcept -> bool {
559  return precisionCast<otherBitness>() == other;
560  }
561  /* --------------------------------------------------------------------------- */
562 
563 
564  /* ----------------------- @name Comparison operators. ----------------------- */
570  template <typename Integral> requires (std::is_integral_v<Integral>)
571  gpu constexpr auto compareTo(Integral integral) const noexcept -> Comparison {
572  if(integral == 0) {
573  switch(sign) {
574  case Sign::Positive:
575  return Comparison::greater;
576  case Sign::Negative:
577  return Comparison::less;
578  default:
579  return Comparison::equal;
580  }
581  } else if(integral < 0) {
582  switch(sign) {
583  case Sign::Negative:
584  switch(base.compareTo(static_cast<unsigned long long>(integral * -1))) {
585  case Comparison::greater:
586  return Comparison::less;
587  case Comparison::less:
588  return Comparison::greater;
589  default:
590  return Comparison::equal;
591  }
592  case Sign::Positive: // + > -
593  default: // 0 > -
594  return Comparison::greater;
595  }
596  } else {
597  switch(sign) {
598  case Sign::Positive:
599  return base.compareTo(static_cast<unsigned long long>(integral));
600  case Sign::Negative: // - < +
601  default: // 0 < +
602  return Comparison::less;
603  }
604  }
605  }
606 
612  template <std::size_t otherBitness = bitness> [[nodiscard]]
613  gpu constexpr auto compareTo(const Aesi<otherBitness>& value) const noexcept -> Comparison {
614  return precisionCast<otherBitness>().compareTo(value);
615  }
616 
622  [[nodiscard]]
623  gpu constexpr auto compareTo(const Aesi& value) const noexcept -> Comparison {
624  if(value.isZero()) {
625  switch(sign) {
626  case Sign::Positive:
627  return Comparison::greater; // Positive > 0
628  case Sign::Negative:
629  return Comparison::less; // Negative < 0
630  default:
631  return Comparison::equal; // 0 == 0
632  }
633  } else if(value.isNegative()) {
634  switch(sign) {
635  case Sign::Negative:
636  switch(base.compareTo(value.base)) {
637  case Comparison::greater:
638  return Comparison::less; // -100 < -20
639  case Comparison::less:
640  return Comparison::greater; // -20 > -100
641  default:
642  return Comparison::equal; // -30 == -30
643  }
644  default: // 0 > Negative
645  return Comparison::greater; // Positive > Negative
646  }
647  } else {
648  switch(sign) {
649  case Sign::Positive:
650  return base.compareTo(value.base);
651  default: // 0 < Positive
652  return Comparison::less; // Negative < Positive
653  }
654  }
655  }
656  /* --------------------------------------------------------------------------- */
657 
658  /* ------------------------ @name Spaceship operators. ----------------------- */
659 #if (defined(__CUDACC__) || __cplusplus < 202002L || defined (PRE_CPP_20)) && !defined DOXYGEN_SKIP
663  gpu constexpr auto operator!=(const Aeu& value) const noexcept -> bool {
664  return !this->operator==(value);
665  }
666  gpu constexpr auto operator<(const Aeu& value) const noexcept -> bool {
667  return this->compareTo(value) == Comparison::less;
668  }
669  gpu constexpr auto operator<=(const Aeu& value) const noexcept -> bool {
670  return !this->operator>(value);
671  }
672  gpu constexpr auto operator>(const Aeu& value) const noexcept -> bool {
673  return this->compareTo(value) == Comparison::greater;
674  }
675  gpu constexpr auto operator>=(const Aeu& value) const noexcept -> bool {
676  return !this->operator<(value);
677  }
678 #else
685  gpu constexpr auto operator<=>(const Aesi& other) const noexcept -> std::strong_ordering {
686  switch(this->compareTo(other)) {
687  case Comparison::less:
688  return std::strong_ordering::less;
689  case Comparison::greater:
690  return std::strong_ordering::greater;
691  case Comparison::equal:
692  return std::strong_ordering::equal;
693  default:
694  return std::strong_ordering::equivalent;
695  }
696  }
697 
704  template <typename Object>
705  gpu constexpr auto operator<=>(const Object& other) const noexcept -> std::strong_ordering {
706  switch(this->compareTo(other)) {
707  case Comparison::less:
708  return std::strong_ordering::less;
709  case Comparison::greater:
710  return std::strong_ordering::greater;
711  case Comparison::equal:
712  return std::strong_ordering::equal;
713  default:
714  return std::strong_ordering::equivalent;
715  }
716  };
717 #endif
718  /* --------------------------------------------------------------------------- */
719  /* ----------------------------------------------------------------------- */
720 
721  /* ---------------------- @name Supporting methods. ---------------------- */
728  gpu constexpr auto setBit(std::size_t index, bool bit) noexcept -> void { return base.setBit(index, bit); }
729 
736  [[nodiscard]]
737  gpu constexpr auto getBit(std::size_t index) const noexcept -> bool { return base.getBit(index); }
738 
745  gpu constexpr auto setByte(std::size_t index, byte byte) noexcept -> void { return base.setByte(index, byte); }
746 
753  [[nodiscard]]
754  gpu constexpr auto getByte(std::size_t index) const noexcept -> byte { return base.getByte(index); }
755 
762  gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void { return base.setBlock(index, block); }
763 
770  [[nodiscard]]
771  gpu constexpr auto getBlock(std::size_t index) const noexcept -> block { return base.getBlock(index); }
772 
777  [[nodiscard]]
778  gpu constexpr auto byteCount() const noexcept -> std::size_t { return base.byteCount(); }
779 
784  [[nodiscard]]
785  gpu constexpr auto bitCount() const noexcept -> std::size_t { return base.bitCount(); }
786 
791  [[nodiscard]]
792  gpu constexpr auto isOdd() const noexcept -> bool { return base.isOdd(); }
793 
798  [[nodiscard]]
799  gpu constexpr auto isEven() const noexcept -> bool { return base.isEven(); }
800 
805  [[nodiscard]]
806  gpu constexpr auto isZero() const noexcept -> bool { return sign == Sign::Zero; }
807 
812  [[nodiscard]]
813  gpu constexpr auto isPositive() const noexcept -> bool { return sign == Sign::Positive; }
814 
819  [[nodiscard]]
820  gpu constexpr auto isNegative() const noexcept -> bool { return sign == Sign::Negative; }
821 
826  [[nodiscard]]
827  gpu constexpr auto filledBlocksNumber() const noexcept -> std::size_t { return base.filledBlocksNumber(); }
828 
833  [[nodiscard]]
834  gpu static constexpr auto getBitness() noexcept -> std::size_t { return bitness; }
835 
840  [[nodiscard]]
841  gpu static constexpr auto totalBlocksNumber() noexcept -> std::size_t { return Aeu<bitness>::totalBlocksNumber(); }
842 
847  gpu constexpr auto swap(Aesi& other) noexcept -> void {
848  Sign tSign = sign; sign = other.sign; other.sign = tSign;
849  base.swap(other.base);
850  }
851 
856  gpu constexpr auto inverse() noexcept -> void { sign = (sign == Sign::Zero ? Sign::Zero : (sign == Sign::Negative ? Sign::Positive : Sign::Negative)); }
857  /* ----------------------------------------------------------------------- */
858 
859  /* -------------- @name Public arithmetic and number theory. ------------- */
868  gpu static constexpr auto divide(const Aesi& number, const Aesi& divisor, Aesi& quotient, Aesi& remainder) noexcept -> void {
869  if(number.sign == Sign::Zero || divisor.sign == Sign::Zero) {
870  quotient.sign = Sign::Zero;
871  remainder.sign = Sign::Zero;
872  return;
873  }
874 
875  Base::divide(number.base, divisor.base, quotient.base, remainder.base);
876  if(number.sign == Sign::Positive) {
877  if(divisor.sign == Sign::Positive) {
878  // (+; +) -> (+; +)
879  quotient.sign = Sign::Positive;
880  remainder.sign = Sign::Positive;
881  } else {
882  // (+; -) -> (-; +)
883  quotient.sign = Sign::Negative;
884  remainder.sign = Sign::Positive;
885  }
886  } else {
887  if(divisor.sign == Sign::Positive) {
888  // (-; +) -> (-; -)
889  quotient.sign = Sign::Negative;
890  remainder.sign = Sign::Negative;
891  } else {
892  // (-; -) -> (+; -)
893  quotient.sign = Sign::Positive;
894  remainder.sign = Sign::Negative;
895  }
896  }
897 
898  if(quotient.base.isZero())
899  quotient.sign = Sign::Zero;
900  if(remainder.base.isZero())
901  remainder.sign = Sign::Zero;
902  }
903 
909  [[nodiscard]]
910  gpu constexpr auto squareRoot() const noexcept -> Aesi {
911  if(sign == Sign::Positive)
912  return Aesi { Sign::Positive, base.squareRoot() };
913  Aesi result; result.sign = Sign::Zero; return result;
914  }
915 
920  [[nodiscard]]
921  gpu static constexpr auto power2(std::size_t power) noexcept -> Aesi {
922  Aesi result { Sign::Positive, Aeu<bitness>::power2(power) };
923  if(result.base.isZero())
924  result.sign = Sign::Zero;
925  return result;
926  }
927  /* ----------------------------------------------------------------------- */
928 
933  template <typename Integral> requires (std::is_integral_v<Integral>) [[nodiscard]]
934  gpu constexpr auto integralCast() const noexcept -> Integral {
935  if(sign == Sign::Zero)
936  return Integral(0);
937 
938  if constexpr (std::is_signed_v<Integral>) {
939  if(sign == Sign::Negative)
940  return base.template integralCast<Integral>() * -1;
941  }
942 
943  return base.template integralCast<Integral>();
944  }
945 
950  template <std::size_t newBitness> requires (newBitness != bitness) [[nodiscard]]
951  gpu constexpr auto precisionCast() const noexcept -> Aesi<newBitness> {
952  if(sign != Sign::Zero) {
953  Aesi<newBitness> result = 1;
954 
955  const std::size_t blockBoarder = (newBitness > bitness ? Aesi<bitness>::totalBlocksNumber() : Aesi<newBitness>::totalBlocksNumber());
956  for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
957  result.setBlock(blockIdx, getBlock(blockIdx));
958 
959  if(sign == Sign::Negative)
960  result.inverse();
961 
962  return result;
963  } else return Aesi<newBitness> {};
964  }
965 
970  gpu constexpr auto unsignedCast() const noexcept -> Aeu<bitness> { return base; }
971 
972  /* ----------------- @name Public input-output operators. ---------------- */
983  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))
984  gpu constexpr auto getString(Char* buffer, std::size_t bufferSize, bool showBase = false, bool hexUppercase = false) const noexcept -> std::size_t {
985  if(sign != Sign::Zero) {
986  if(sign == Sign::Negative && bufferSize > 0) {
987  *buffer++ = [] { if constexpr (std::is_same_v<Char, char>) { return '-'; } else { return L'-'; } } ();
988  --bufferSize;
989  }
990  return base.template getString<notation, Char>(buffer, bufferSize, showBase, hexUppercase);
991  }
992 
993  if(showBase) {
994  switch(notation) {
995  case 2: {
996  if(bufferSize < 3) return 0;
997  buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
998  buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'b'; } else { return L'b'; } } ();
999  buffer[2] = buffer[0];
1000  return 3;
1001  }
1002  case 8: {
1003  if(bufferSize < 3) return 0;
1004  buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1005  buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'o'; } else { return L'o'; } } ();
1006  buffer[2] = buffer[0];
1007  return 3;
1008  }
1009  case 16: {
1010  if(bufferSize < 3) return 0;
1011  buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1012  buffer[1] = [] { if constexpr (std::is_same_v<Char, char>) { return 'x'; } else { return L'x'; } } ();
1013  buffer[2] = buffer[0];
1014  return 3;
1015  }
1016  default: {
1017  if(bufferSize < 1) return 0;
1018  buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1019  return 1;
1020  }
1021  }
1022  }
1023 
1024  buffer[0] = [] { if constexpr (std::is_same_v<Char, char>) { return '0'; } else { return L'0'; } } ();
1025  return 1;
1026  }
1027 
1039  template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
1040  friend constexpr auto operator<<(std::basic_ostream<Char>& os, const Aesi& number) -> std::basic_ostream<Char>& {
1041  if(number.sign != Sign::Zero) {
1042  if(number.sign == Sign::Negative)
1043  os << [] { if constexpr (std::is_same_v<Char, char>) { return '-'; } else { return L'-'; } } ();
1044  return os << number.base;
1045  }
1046  return os << '0';
1047  }
1048  /* ----------------------------------------------------------------------- */
1049 
1050 #if defined __CUDACC__ || defined DOXYGEN_SKIP
1057  __device__ constexpr auto tryAtomicSet(const Aesi& value) noexcept -> void {
1058  base.tryAtomicSet(value.base);
1059  sign = value.sign; /* TODO: Make enum substitution using existing CUDA atomics */
1060  }
1061 
1068  __device__ constexpr auto tryAtomicExchange(const Aesi& value) noexcept -> void {
1069  base.tryAtomicExchange(value.base);
1070  sign = value.sign; /* TODO: Make enum substitution using existing CUDA atomics */
1071  }
1072 #endif
1073 };
1074 
1075 /* -------------------------------------------- @name Type-definitions ------------------------------------------- */
1080 
1085 
1090 
1095 
1100 
1105 
1110 
1115 
1120 
1125 
1130 /* ---------------------------------------------------------------------------------------------------------------- */
1131 
1132 /* ------------------------------------------ @name Integral conversions ----------------------------------------- */
1139 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1140 gpu constexpr auto operator+(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) + value; }
1141 
1148 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1149 gpu constexpr auto operator-(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) - value; }
1150 
1157 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1158 gpu constexpr auto operator*(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) * value; }
1159 
1166 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1167 gpu constexpr auto operator/(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) / value; }
1168 
1175 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1176 gpu constexpr auto operator%(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) % value; }
1177 
1184 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1185 gpu constexpr auto operator^(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) ^ value; }
1186 
1193 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1194 gpu constexpr auto operator&(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) & value; }
1195 
1202 template <std::size_t bitness, typename Integral> requires (std::is_integral_v<Integral>)
1203 gpu constexpr auto operator|(Integral number, const Aesi<bitness>& value) noexcept { return Aesi<bitness>(number) | value; }
1204 /* ---------------------------------------------------------------------------------------------------------------- */
1205 
1206 #endif //AESI_MULTIPRECISION
requires(bitness % blockBitLength==0) class Aesi final
Definition: Aesi.h:22
Long precision unsigned integer with arithmetic operations.
Long precision signed integer.
Long precision unsigned integer.