1 #ifndef AESI_MULTIPRECISION
2 #define AESI_MULTIPRECISION
14 enum class Sign { Zero = 0, Positive = 1, Negative = -1 };
22 template <std::
size_t bitness = 512>
requires (bitness % blockBitLength == 0)
31 gpu constexpr
Aesi(Sign withSign, Base withBase): sign { withSign }, base { withBase } {};
38 gpu constexpr
Aesi() noexcept =
default;
44 gpu constexpr
Aesi(
const Aesi& copy) noexcept =
default;
50 template <
typename Integral>
requires (std::is_integral_v<Integral>)
51 gpu constexpr
Aesi(Integral value) noexcept {
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;
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) {
75 const auto dash = [] {
76 if constexpr (std::is_same_v<Char, char>) {
82 for(std::size_t i = 0; i < size; ++i)
83 if(ptr[i] == dash) positive ^= 1;
85 sign = (positive ? Sign::Positive : Sign::Negative);
86 }
else sign = Sign::Zero;
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) {}
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()) {}
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()) {}
112 explicit gpu constexpr
Aesi(
const Aeu<bitness>& value) : sign(Sign::Positive), base(value) {}
114 #ifdef AESI_CRYPTOPP_INTEGRATION
119 constexpr
Aesi(
const CryptoPP::Integer& number) {
124 if(number.IsNegative())
125 sign = Sign::Negative;
126 else sign = Sign::Positive;
131 #ifdef AESI_GMP_INTEGRATION
136 constexpr
Aesi(
const mpz_class& number) {
142 sign = Sign::Negative;
143 else sign = Sign::Positive;
152 template <
typename Integral>
requires (std::is_signed_v<Integral>)
153 gpu constexpr
Aesi& operator=(Integral value) noexcept {
156 sign = Sign::Negative;
158 }
else sign = Sign::Positive;
159 base =
static_cast<unsigned long long>(value);
160 }
else sign = Sign::Zero;
168 gpu constexpr
Aesi& operator=(
const Aesi& other) noexcept { base = other.base; sign = other.sign;
return *
this; }
179 gpu constexpr
auto operator+()
const noexcept ->
Aesi {
return *
this; }
186 gpu constexpr
auto operator-()
const noexcept ->
Aesi {
Aesi copy = *
this; copy.inverse();
return copy; }
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) {
197 }
else { base = 1u; sign = Sign::Positive; }
205 gpu constexpr
auto operator++(
int) & noexcept ->
Aesi {
Aesi old = *
this; operator++();
return old; }
211 gpu constexpr
auto operator--() noexcept ->
Aesi& {
212 if(sign == Sign::Negative) {
214 }
else if(sign == Sign::Positive) {
215 --base;
if(base.isZero()) sign = Sign::Zero;
216 }
else { base = 1u; sign = Sign::Negative; }
224 gpu constexpr
auto operator--(
int) & noexcept ->
Aesi {
Aesi old = *
this; operator--();
return old; }
234 gpu constexpr
auto operator+(
const Aesi& addendum)
const noexcept ->
Aesi {
Aesi result = *
this; result += addendum;
return result; }
241 gpu constexpr
auto operator+=(
const Aesi& addendum) noexcept ->
Aesi& {
242 if(addendum.sign == Sign::Zero)
244 if(sign == Sign::Zero)
245 return this->operator=(addendum);
247 if(sign == addendum.sign) {
248 base += addendum.base;
252 if(sign == Sign::Positive) {
253 switch(base.compareTo(addendum.base)) {
254 case Comparison::greater: {
255 base -= addendum.base;
258 case Comparison::less: {
259 base = addendum.base - base;
260 sign = Sign::Negative;
269 switch(
const auto ratio = base.compareTo(addendum.base)) {
270 case Comparison::greater: {
271 base -= addendum.base;
274 case Comparison::less: {
275 base = addendum.base - base;
276 sign = Sign::Positive;
295 gpu constexpr
auto operator-(
const Aesi& subtrahend)
const noexcept ->
Aesi {
Aesi result = *
this; result -= subtrahend;
return result; }
302 gpu constexpr
auto operator-=(
const Aesi& subtrahend) noexcept ->
Aesi& {
303 if(subtrahend.sign == Sign::Zero)
305 if(sign == Sign::Zero) {
311 if(sign == Sign::Positive) {
312 if(subtrahend.sign == Sign::Positive) {
313 switch(base.compareTo(subtrahend.base)) {
314 case Comparison::greater: {
315 base -= subtrahend.base;
318 case Comparison::less: {
319 base = subtrahend.base - base;
320 sign = Sign::Negative;
329 base += subtrahend.base;
333 if(subtrahend.sign == Sign::Negative) {
334 switch(base.compareTo(subtrahend.base)) {
335 case Comparison::greater: {
336 base -= subtrahend.base;
339 case Comparison::less: {
340 base = subtrahend.base - base;
341 sign = Sign::Positive;
350 base += subtrahend.base;
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; }
372 gpu constexpr
auto operator*(
const Aesi& factor)
const noexcept ->
Aesi {
Aesi result = *
this; result *= factor;
return result; }
379 template <
typename Integral>
requires (std::is_integral_v<Integral>)
380 gpu constexpr
auto operator*=(Integral factor) noexcept ->
Aesi& {
388 base.operator*=(
static_cast<unsigned long long>(factor));
398 gpu constexpr
auto operator*=(
const Aesi& factor) noexcept ->
Aesi& {
399 if(factor.isZero()) {
402 if(factor.isNegative())
404 base.operator*=(factor.base);
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; }
427 gpu constexpr
auto operator/(
const Aesi& divisor)
const noexcept ->
Aesi {
Aesi result = *
this; result /= divisor;
return result; }
435 template <
typename Integral>
requires (std::is_integral_v<Integral>)
436 gpu constexpr
auto operator/=(Integral divisor) noexcept ->
Aesi& {
444 base.operator/=(
static_cast<unsigned long long>(divisor));
445 if(base.isZero()) sign = Sign::Zero;
456 gpu constexpr
auto operator/=(
const Aesi& divisor) noexcept ->
Aesi& {
457 if(divisor.isZero()) {
460 if(divisor.isNegative())
462 base.operator/=(divisor.base);
463 if(base.isZero()) sign = Sign::Zero;
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; }
487 gpu constexpr
auto operator%(
const Aesi& modulo)
const noexcept ->
Aesi {
Aesi result = *
this; result %= modulo;
return result; }
495 template <
typename Integral>
requires (std::is_integral_v<Integral>)
496 gpu constexpr
auto operator%=(Integral modulo) noexcept ->
Aesi& {
504 base.operator%=(
static_cast<unsigned long long>(modulo));
516 gpu constexpr
auto operator%=(
const Aesi& modulo) noexcept ->
Aesi& {
520 if(modulo.isNegative())
522 base.operator%=(modulo.base);
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;
548 gpu constexpr
auto operator==(
const Aesi& other)
const noexcept ->
bool {
549 return sign == other.sign && base == other.base;
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;
570 template <
typename Integral>
requires (std::is_integral_v<Integral>)
571 gpu constexpr
auto compareTo(Integral integral)
const noexcept -> Comparison {
575 return Comparison::greater;
577 return Comparison::less;
579 return Comparison::equal;
581 }
else if(integral < 0) {
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;
590 return Comparison::equal;
594 return Comparison::greater;
599 return base.compareTo(
static_cast<unsigned long long>(integral));
602 return Comparison::less;
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);
623 gpu constexpr
auto compareTo(
const Aesi& value)
const noexcept -> Comparison {
627 return Comparison::greater;
629 return Comparison::less;
631 return Comparison::equal;
633 }
else if(value.isNegative()) {
636 switch(base.compareTo(value.base)) {
637 case Comparison::greater:
638 return Comparison::less;
639 case Comparison::less:
640 return Comparison::greater;
642 return Comparison::equal;
645 return Comparison::greater;
650 return base.compareTo(value.base);
652 return Comparison::less;
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);
666 gpu constexpr
auto operator<(
const Aeu& value)
const noexcept ->
bool {
667 return this->compareTo(value) == Comparison::less;
669 gpu constexpr
auto operator<=(
const Aeu& value)
const noexcept ->
bool {
670 return !this->operator>(value);
672 gpu constexpr
auto operator>(
const Aeu& value)
const noexcept ->
bool {
673 return this->compareTo(value) == Comparison::greater;
675 gpu constexpr
auto operator>=(
const Aeu& value)
const noexcept ->
bool {
676 return !this->operator<(value);
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;
694 return std::strong_ordering::equivalent;
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;
714 return std::strong_ordering::equivalent;
728 gpu constexpr
auto setBit(std::size_t index,
bool bit) noexcept ->
void {
return base.setBit(index, bit); }
737 gpu constexpr
auto getBit(std::size_t index)
const noexcept ->
bool {
return base.getBit(index); }
745 gpu constexpr
auto setByte(std::size_t index,
byte byte) noexcept ->
void {
return base.setByte(index,
byte); }
754 gpu constexpr
auto getByte(std::size_t index)
const noexcept ->
byte {
return base.getByte(index); }
762 gpu constexpr
auto setBlock(std::size_t index, block block) noexcept ->
void {
return base.setBlock(index, block); }
771 gpu constexpr
auto getBlock(std::size_t index)
const noexcept -> block {
return base.getBlock(index); }
778 gpu constexpr
auto byteCount()
const noexcept -> std::size_t {
return base.byteCount(); }
785 gpu constexpr
auto bitCount()
const noexcept -> std::size_t {
return base.bitCount(); }
792 gpu constexpr
auto isOdd()
const noexcept ->
bool {
return base.isOdd(); }
799 gpu constexpr
auto isEven()
const noexcept ->
bool {
return base.isEven(); }
806 gpu constexpr
auto isZero()
const noexcept ->
bool {
return sign == Sign::Zero; }
813 gpu constexpr
auto isPositive()
const noexcept ->
bool {
return sign == Sign::Positive; }
820 gpu constexpr
auto isNegative()
const noexcept ->
bool {
return sign == Sign::Negative; }
827 gpu constexpr
auto filledBlocksNumber()
const noexcept -> std::size_t {
return base.filledBlocksNumber(); }
834 gpu
static constexpr
auto getBitness() noexcept -> std::size_t {
return bitness; }
847 gpu constexpr
auto swap(
Aesi& other) noexcept ->
void {
848 Sign tSign = sign; sign = other.sign; other.sign = tSign;
849 base.swap(other.base);
856 gpu constexpr
auto inverse() noexcept ->
void { sign = (sign == Sign::Zero ? Sign::Zero : (sign == Sign::Negative ? Sign::Positive : Sign::Negative)); }
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;
875 Base::divide(number.base, divisor.base, quotient.base, remainder.base);
876 if(number.sign == Sign::Positive) {
877 if(divisor.sign == Sign::Positive) {
879 quotient.sign = Sign::Positive;
880 remainder.sign = Sign::Positive;
883 quotient.sign = Sign::Negative;
884 remainder.sign = Sign::Positive;
887 if(divisor.sign == Sign::Positive) {
889 quotient.sign = Sign::Negative;
890 remainder.sign = Sign::Negative;
893 quotient.sign = Sign::Positive;
894 remainder.sign = Sign::Negative;
898 if(quotient.base.isZero())
899 quotient.sign = Sign::Zero;
900 if(remainder.base.isZero())
901 remainder.sign = Sign::Zero;
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;
921 gpu
static constexpr
auto power2(std::size_t power) noexcept ->
Aesi {
923 if(result.base.isZero())
924 result.sign = Sign::Zero;
933 template <
typename Integral>
requires (std::is_integral_v<Integral>) [[nodiscard]]
934 gpu constexpr
auto integralCast()
const noexcept -> Integral {
935 if(sign == Sign::Zero)
938 if constexpr (std::is_signed_v<Integral>) {
939 if(sign == Sign::Negative)
940 return base.template integralCast<Integral>() * -1;
943 return base.template integralCast<Integral>();
950 template <std::
size_t newBitness>
requires (newBitness != bitness) [[nodiscard]]
952 if(sign != Sign::Zero) {
956 for(std::size_t blockIdx = 0; blockIdx < blockBoarder; ++blockIdx)
957 result.setBlock(blockIdx, getBlock(blockIdx));
959 if(sign == Sign::Negative)
970 gpu constexpr
auto unsignedCast()
const noexcept ->
Aeu<bitness> {
return base; }
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
'-'; } } ();
990 return base.template getString<notation, Char>(buffer, bufferSize, showBase, hexUppercase);
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];
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];
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];
1017 if(bufferSize < 1)
return 0;
1018 buffer[0] = [] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; } } ();
1024 buffer[0] = [] {
if constexpr (std::is_same_v<Char, char>) {
return '0'; }
else {
return L
'0'; } } ();
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;
1050 #if defined __CUDACC__ || defined DOXYGEN_SKIP
1057 __device__ constexpr
auto tryAtomicSet(
const Aesi& value) noexcept ->
void {
1058 base.tryAtomicSet(value.base);
1068 __device__ constexpr
auto tryAtomicExchange(
const Aesi& value) noexcept ->
void {
1069 base.tryAtomicExchange(value.base);
1139 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1148 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1157 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1166 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1175 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1184 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1193 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
1202 template <std::
size_t bitness,
typename Integral>
requires (std::is_integral_v<Integral>)
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.