MeshLib C++ Docs
Loading...
Searching...
No Matches
MRVarBigInt.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRMeshFwd.h"
4#include "MRBuffer.h"
5#include "MRFastInt.h"
6#include "MRFastInt128.h"
7#include <MRPch/MRBindingMacros.h>
8#include <algorithm>
9#include <array>
10#include <cassert>
11#include <compare>
12#include <cstdint>
13#include <variant>
14
15namespace MR
16{
17
20
35{
36public:
37 VarBigInt() noexcept = default;
38
40 VarBigInt( const VarBigInt & o ) { assignLimbs( o.sign_, o.limbs(), o.len_ ); }
41 VarBigInt( VarBigInt && ) noexcept = default;
42 VarBigInt & operator =( const VarBigInt & o ) { if ( this != &o ) assignLimbs( o.sign_, o.limbs(), o.len_ ); return *this; }
43 VarBigInt & operator =( VarBigInt && ) noexcept = default;
44
47 VarBigInt( std::int64_t v )
48 {
49 if ( v == 0 )
50 return;
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 );
54 }
55
57 explicit VarBigInt( FastInt128 v )
58 {
59 if ( v == 0 )
60 return;
61 const FastUInt128 u = v < 0 ? FastUInt128( 0 ) - FastUInt128( v ) : FastUInt128( v );
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 ) );
64 }
65
68 template <int nBits>
69 explicit VarBigInt( const FastInt<nBits> & v )
70 {
71 const int s = v.sign();
72 if ( s == 0 )
73 return;
74 auto w = v.w;
75 if ( s < 0 )
76 {
77 std::uint64_t borrow = 0;
78 for ( auto & x : w )
79 x = detail::subBorrow64( 0, x, borrow );
80 }
81 assignLimbs( s, w.data(), magNorm( w.data(), w.size() ) );
82 }
83
85 [[nodiscard]] int sign() const noexcept { return sign_; }
86
87 [[nodiscard]] VarBigInt operator -() const
88 {
89 VarBigInt res = *this;
90 res.sign_ = -res.sign_;
91 return res;
92 }
93
94 VarBigInt & operator +=( const VarBigInt & b ) { return *this = *this + b; }
95 VarBigInt & operator -=( const VarBigInt & b ) { return *this = *this - b; }
96
97 [[nodiscard]] friend VarBigInt operator +( const VarBigInt & a, const VarBigInt & b )
98 {
99 if ( a.sign_ == 0 )
100 return b;
101 if ( b.sign_ == 0 )
102 return a;
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_ );
107 if ( c == 0 )
108 return VarBigInt{};
109 if ( c > 0 )
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 ); } );
114 }
115
116 [[nodiscard]] friend VarBigInt operator -( const VarBigInt & a, const VarBigInt & b ) { return a + ( -b ); }
117
118 [[nodiscard]] friend VarBigInt operator *( const VarBigInt & a, const VarBigInt & b )
119 {
120 if ( a.sign_ == 0 || b.sign_ == 0 )
121 return VarBigInt{};
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 ); } );
124 }
125
126 [[nodiscard]] friend bool operator ==( const VarBigInt & a, const VarBigInt & b ) noexcept
127 {
128 if ( a.sign_ != b.sign_ || a.len_ != b.len_ )
129 return false;
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] )
134 return false;
135 return true;
136 }
137
138 [[nodiscard]] friend std::strong_ordering operator <=>( const VarBigInt & a, const VarBigInt & b ) noexcept
139 {
140 if ( a.sign_ != b.sign_ )
141 return a.sign_ <=> b.sign_;
142 if ( a.sign_ == 0 )
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;
146 return r <=> 0;
147 }
148
149private:
150 int sign_ = 0;
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>{} };
154
156 [[nodiscard]] const std::uint64_t * limbs() const noexcept
157 {
158 return std::visit( []( const auto & s ) -> const std::uint64_t * { return s.data(); }, mag_ );
159 }
160
163 void assignLimbs( int sign, const std::uint64_t * p, std::size_t n )
164 {
165 if ( n == 0 )
166 {
167 sign_ = 0;
168 len_ = 0;
169 mag_.emplace<1>();
170 return;
171 }
172 sign_ = sign;
173 len_ = n;
174 if ( n <= 2 )
175 {
176 std::array<std::uint64_t, 2> a{ 0, 0 };
177 for ( std::size_t i = 0; i < n; ++i )
178 a[i] = p[i];
179 mag_.emplace<1>( a );
180 }
181 else
182 {
183 Buffer<std::uint64_t> b( n );
184 for ( std::size_t i = 0; i < n; ++i )
185 b[i] = p[i];
186 mag_.emplace<0>( std::move( b ) );
187 }
188 }
189
192 template <typename Kernel>
193 [[nodiscard]] static VarBigInt make( int sign, std::size_t ub, bool zeroInit, Kernel kernel )
194 {
195 VarBigInt res;
196 if ( sign == 0 )
197 return res;
198 if ( ub <= 2 )
199 {
200 std::array<std::uint64_t, 2> tmp{ 0, 0 };
201 const std::size_t n = kernel( tmp.data() );
202 assert( n <= 2 );
203 if ( n == 0 )
204 return res;
208 res.sign_ = sign;
209 res.len_ = n;
210 res.mag_.emplace<1>( tmp );
211 }
212 else
213 {
214 Buffer<std::uint64_t> buf( ub );
215 if ( zeroInit )
216 std::fill( buf.data(), buf.data() + ub, std::uint64_t( 0 ) );
217 const std::size_t n = kernel( buf.data() );
218 if ( n <= 2 )
219 res.assignLimbs( sign, buf.data(), n );
220 else
221 {
222 res.sign_ = sign;
223 res.len_ = n;
224 res.mag_.emplace<0>( std::move( buf ) );
225 }
226 }
227 return res;
228 }
229
231 [[nodiscard]] static std::size_t magNorm( const std::uint64_t * p, std::size_t n ) noexcept
232 {
233 while ( n > 0 && p[n - 1] == 0 )
234 --n;
235 return n;
236 }
237
239 [[nodiscard]] static int magCmp( const std::uint64_t * a, std::size_t na, const std::uint64_t * b, std::size_t nb ) noexcept
240 {
241 if ( na != nb )
242 return na < nb ? -1 : 1;
243 for ( std::size_t i = na; i-- > 0; )
244 if ( a[i] != b[i] )
245 return a[i] < b[i] ? -1 : 1;
246 return 0;
247 }
248
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 )
251 {
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 )
255 {
256 const std::uint64_t x = i < na ? a[i] : 0;
257 const std::uint64_t y = i < nb ? b[i] : 0;
258 out[i] = detail::addCarry64( x, y, carry );
259 }
260 std::size_t m = n;
261 if ( carry )
262 out[m++] = carry;
263 return m;
264 }
265
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 )
268 {
269 std::uint64_t borrow = 0;
270 for ( std::size_t i = 0; i < na; ++i )
271 {
272 const std::uint64_t x = a[i];
273 const std::uint64_t y = i < nb ? b[i] : 0;
274 out[i] = detail::subBorrow64( x, y, borrow );
275 }
276 return magNorm( out, na );
277 }
278
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 )
281 {
282 for ( std::size_t i = 0; i < na; ++i )
283 {
284 std::uint64_t carry = 0;
285 for ( std::size_t j = 0; j < nb; ++j )
286 {
288 const FastUInt128 t = FastUInt128( a[i] ) * FastUInt128( b[j] )
289 + FastUInt128( out[i + j] ) + FastUInt128( carry );
290 out[i + j] = std::uint64_t( t );
291 carry = std::uint64_t( t >> 64 );
292 }
293 out[i + nb] += carry;
294 }
295 return magNorm( out, na + nb );
296 }
297};
298
300
301}
Definition MRFastInt.h:141
constexpr int sign() const noexcept
-1, 0 or 1 if the value is negative, zero or positive respectively
Definition MRFastInt.h:194
std::array< std::uint64_t, numWords > w
two's complement representation: w[0] + 2^64 * w[1] + ... + 2^(nBits-64) * std::int64_t( w[numWords-1...
Definition MRFastInt.h:149
VarBigInt(const FastInt< nBits > &v)
Definition MRVarBigInt.h:69
int sign() const noexcept
-1, 0 or 1 if the value is negative, zero or positive respectively
Definition MRVarBigInt.h:85
VarBigInt() noexcept=default
VarBigInt(FastInt128 v)
from a 128-bit integer (explicit to keep int -> VarBigInt unambiguous via the int64 ctor)
Definition MRVarBigInt.h:57
VarBigInt(VarBigInt &&) noexcept=default
BitSet operator-(const BitSet &a, const BitSet &b)
Definition MRBitSet.h:477
bool operator==(const BitSet &a, const BitSet &b)
compare that two bit sets have the same set bits (they can be equal even if sizes are distinct but la...
TransformedMesh & operator-=(TransformedMesh &a, const TransformedMesh &b)
difference operation on two meshes
__int128_t FastInt128
Definition MRFastInt128.h:25
Color operator*(float a, const Color &b)
Definition MRColor.h:119
__uint128_t FastUInt128
Definition MRFastInt128.h:26
std::array< Vector3f, 3 > MR_BIND_IGNORE
Definition MRMeshBuilderTypes.h:13
TransformedMesh & operator+=(TransformedMesh &a, const TransformedMesh &b)
union operation on two meshes
Color operator+(const Color &a, const Color &b)
Definition MRColor.h:109
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
only for bindings generation
Definition MRCameraOrientationPlugin.h:8