42 VarBigInt & operator =( const
VarBigInt & o ) {
if (
this != &o ) assignLimbs( o.sign_, o.limbs(), o.len_ );
return *
this; }
52 const std::uint64_t m = v < 0 ? ~std::uint64_t( v ) + 1 : std::uint64_t( v );
53 assignLimbs( v < 0 ? -1 : 1, &m, 1 );
62 const std::uint64_t w[2] = { std::uint64_t( u ), std::uint64_t( u >> 64 ) };
63 assignLimbs( v < 0 ? -1 : 1, w, magNorm( w, 2 ) );
71 const int s = v.
sign();
77 std::uint64_t borrow = 0;
81 assignLimbs( s, w.data(), magNorm( w.data(), w.size() ) );
85 [[nodiscard]]
int sign() const noexcept {
return sign_; }
90 res.sign_ = -res.sign_;
103 if ( a.sign_ == b.sign_ )
104 return make( a.sign_, std::max( a.len_, b.len_ ) + 1,
false,
105 [&]( std::uint64_t * out ) { return magAdd( a.limbs(), a.len_, b.limbs(), b.len_, out ); } );
106 const int c = magCmp( a.limbs(), a.len_, b.limbs(), b.len_ );
110 return make( a.sign_, a.len_,
false,
111 [&]( std::uint64_t * out ) { return magSub( a.limbs(), a.len_, b.limbs(), b.len_, out ); } );
112 return make( b.sign_, b.len_,
false,
113 [&]( std::uint64_t * out ) { return magSub( b.limbs(), b.len_, a.limbs(), a.len_, out ); } );
120 if ( a.sign_ == 0 || b.sign_ == 0 )
122 return make( a.sign_ * b.sign_, a.len_ + b.len_,
true,
123 [&]( std::uint64_t * out ) { return magMul( a.limbs(), a.len_, b.limbs(), b.len_, out ); } );
128 if ( a.sign_ != b.sign_ || a.len_ != b.len_ )
130 const std::uint64_t * pa = a.limbs();
131 const std::uint64_t * pb = b.limbs();
132 for ( std::size_t i = 0; i < a.len_; ++i )
133 if ( pa[i] != pb[i] )
138 [[nodiscard]]
friend std::strong_ordering operator <=>(
const VarBigInt & a,
const VarBigInt & b )
noexcept
140 if ( a.sign_ != b.sign_ )
141 return a.sign_ <=> b.sign_;
143 return std::strong_ordering::equal;
144 const int c = magCmp( a.limbs(), a.len_, b.limbs(), b.len_ );
145 const int r = a.sign_ > 0 ? c : -c;
151 std::size_t len_ = 0;
153 std::variant<Buffer<std::uint64_t>, std::array<std::uint64_t, 2>> mag_{ std::array<std::uint64_t, 2>{} };
156 [[nodiscard]]
const std::uint64_t * limbs() const noexcept
158 return std::visit( [](
const auto & s ) ->
const std::uint64_t * {
return s.data(); }, mag_ );
163 void assignLimbs(
int sign,
const std::uint64_t * p, std::size_t n )
176 std::array<std::uint64_t, 2> a{ 0, 0 };
177 for ( std::size_t i = 0; i < n; ++i )
179 mag_.emplace<1>( a );
183 Buffer<std::uint64_t> b( n );
184 for ( std::size_t i = 0; i < n; ++i )
186 mag_.emplace<0>( std::move( b ) );
192 template <
typename Kernel>
193 [[nodiscard]]
static VarBigInt make(
int sign, std::size_t ub,
bool zeroInit, Kernel kernel )
200 std::array<std::uint64_t, 2> tmp{ 0, 0 };
201 const std::size_t n = kernel( tmp.data() );
210 res.mag_.emplace<1>( tmp );
214 Buffer<std::uint64_t> buf( ub );
216 std::fill( buf.data(), buf.data() + ub, std::uint64_t( 0 ) );
217 const std::size_t n = kernel( buf.data() );
219 res.assignLimbs( sign, buf.data(), n );
224 res.mag_.emplace<0>( std::move( buf ) );
231 [[nodiscard]]
static std::size_t magNorm(
const std::uint64_t * p, std::size_t n )
noexcept
233 while ( n > 0 && p[n - 1] == 0 )
239 [[nodiscard]]
static int magCmp(
const std::uint64_t * a, std::size_t na,
const std::uint64_t * b, std::size_t nb )
noexcept
242 return na < nb ? -1 : 1;
243 for ( std::size_t i = na; i-- > 0; )
245 return a[i] < b[i] ? -1 : 1;
250 static std::size_t magAdd(
const std::uint64_t * a, std::size_t na,
const std::uint64_t * b, std::size_t nb, std::uint64_t * out )
252 const std::size_t n = std::max( na, nb );
253 std::uint64_t carry = 0;
254 for ( std::size_t i = 0; i < n; ++i )
256 const std::uint64_t x = i < na ? a[i] : 0;
257 const std::uint64_t y = i < nb ? b[i] : 0;
267 static std::size_t magSub(
const std::uint64_t * a, std::size_t na,
const std::uint64_t * b, std::size_t nb, std::uint64_t * out )
269 std::uint64_t borrow = 0;
270 for ( std::size_t i = 0; i < na; ++i )
272 const std::uint64_t x = a[i];
273 const std::uint64_t y = i < nb ? b[i] : 0;
276 return magNorm( out, na );
280 static std::size_t magMul(
const std::uint64_t * a, std::size_t na,
const std::uint64_t * b, std::size_t nb, std::uint64_t * out )
282 for ( std::size_t i = 0; i < na; ++i )
284 std::uint64_t carry = 0;
285 for ( std::size_t j = 0; j < nb; ++j )
290 out[i + j] = std::uint64_t( t );
291 carry = std::uint64_t( t >> 64 );
293 out[i + nb] += carry;
295 return magNorm( out, na + nb );
constexpr std::uint64_t addCarry64(std::uint64_t a, std::uint64_t b, std::uint64_t &carry) noexcept
returns a + b + carry modulo 2^64, and replaces carry with the carry-out (0 or 1)
Definition MRFastInt.h:29
constexpr std::uint64_t subBorrow64(std::uint64_t a, std::uint64_t b, std::uint64_t &borrow) noexcept
returns a - b - borrow modulo 2^64, and replaces borrow with the borrow-out (0 or 1)
Definition MRFastInt.h:37