MeshLib C++ Docs
Loading...
Searching...
No Matches
MRFastInt.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRMeshFwd.h"
4#include "MRFastInt128.h"
5#include <MRPch/MRBindingMacros.h>
6#include <array>
7#include <cassert>
8#include <compare>
9#include <cstdint>
10#include <type_traits>
11
12namespace MR
13{
14
17
18namespace detail
19{
20
22template <typename T>
23constexpr bool cFitsFastInt128 = std::is_integral_v<T> || std::is_same_v<T, FastInt128>;
24
27
29[[nodiscard]] inline constexpr std::uint64_t addCarry64( std::uint64_t a, std::uint64_t b, std::uint64_t & carry ) noexcept
30{
31 const FastUInt128 t = FastUInt128( a ) + FastUInt128( b ) + FastUInt128( carry );
32 carry = std::uint64_t( t >> 64 );
33 return std::uint64_t( t );
34}
35
37[[nodiscard]] inline constexpr std::uint64_t subBorrow64( std::uint64_t a, std::uint64_t b, std::uint64_t & borrow ) noexcept
38{
39 const FastUInt128 t = FastUInt128( a ) - FastUInt128( b ) - FastUInt128( borrow );
40 borrow = std::uint64_t( t >> 64 ) & 1;
41 return std::uint64_t( t );
42}
43
45[[nodiscard]] inline constexpr std::uint64_t signWord( std::uint64_t hi ) noexcept
46{
47 return std::int64_t( hi ) < 0 ? ~std::uint64_t( 0 ) : 0;
48}
49
52template <std::size_t n, std::size_t m>
53[[nodiscard]] constexpr std::array<std::uint64_t, n + m> mulWords(
54 const std::array<std::uint64_t, n> & a, const std::array<std::uint64_t, m> & b ) noexcept
55{
56 std::array<std::uint64_t, n + m> res = {};
57 for ( std::size_t i = 0; i < n; ++i )
58 {
59 if ( a[i] == 0 )
60 continue;
65 std::uint64_t carry = 0;
66 for ( std::size_t j = 0; j < m; ++j )
67 {
69 const FastUInt128 t = FastUInt128( a[i] ) * FastUInt128( b[j] ) + FastUInt128( res[i + j] ) + FastUInt128( carry );
70 res[i + j] = std::uint64_t( t );
71 carry = std::uint64_t( t >> 64 );
72 }
73 res[i + m] = carry;
74 }
75
78 if ( std::int64_t( a[n - 1] ) < 0 )
79 {
80 std::uint64_t borrow = 0;
81 for ( std::size_t i = 0; i < m; ++i )
82 res[n + i] = subBorrow64( res[n + i], b[i], borrow );
83 }
84 if ( std::int64_t( b[m - 1] ) < 0 )
85 {
86 std::uint64_t borrow = 0;
87 for ( std::size_t i = 0; i < n; ++i )
88 res[m + i] = subBorrow64( res[m + i], a[i], borrow );
89 }
90 return res;
91}
92
95template <typename T>
96constexpr int cMulBits = std::is_same_v<T, FastInt128> || ( std::is_unsigned_v<T> && sizeof( T ) >= 8 ) ? 128 : 64;
97
99template <typename T>
100[[nodiscard]] constexpr auto mulWordsOf( T v ) noexcept
101{
102 if constexpr ( cMulBits<T> == 128 )
103 {
104 const FastInt128 x = FastInt128( v );
105 return std::array{ std::uint64_t( x ), std::uint64_t( x >> 64 ) };
106 }
107 else
108 return std::array{ std::uint64_t( std::int64_t( v ) ) };
109}
110
113[[nodiscard]] MRMESH_API double doubleFromWords( const std::uint64_t * w, int n ) noexcept;
114
115}
116
121[[nodiscard]] MR_BIND_IGNORE inline double toDouble( FastInt128 v ) noexcept
122{
123#ifdef MR_HAS_BUILTIN_INT128
124 return double( v );
126#else
129 const FastUInt128 u( v );
130 const std::uint64_t w[2] = { std::uint64_t( u ), std::uint64_t( u >> 64 ) };
131 return detail::doubleFromWords( w, 2 );
132#endif
133}
134
139template <int nBits>
141{
142public:
143 static_assert( nBits >= 192 && nBits % 64 == 0 );
144
146 static constexpr int numWords = nBits / 64;
147
149 std::array<std::uint64_t, numWords> w = {};
150
151 FastInt() noexcept = default;
152
154 template <typename T>
155 requires detail::cFitsFastInt128<T>
156 constexpr FastInt( T v ) noexcept
157 {
158 const FastInt128 x = FastInt128( v );
159 w[0] = std::uint64_t( x );
160 w[1] = std::uint64_t( x >> 64 );
161 const auto s = detail::signWord( w[1] );
162 for ( int i = 2; i < numWords; ++i )
163 w[i] = s;
164 }
165
167 template <int mBits>
168 requires ( mBits < nBits )
169 constexpr FastInt( const FastInt<mBits> & v ) noexcept
170 {
171 constexpr int m = FastInt<mBits>::numWords;
172 for ( int i = 0; i < m; ++i )
173 w[i] = v.w[i];
174 const auto s = detail::signWord( v.w[m - 1] );
175 for ( int i = m; i < numWords; ++i )
176 w[i] = s;
177 }
178
182 template <int mBits>
183 requires ( mBits > nBits )
184 constexpr explicit FastInt( const FastInt<mBits> & v ) noexcept
185 {
186 for ( int i = 0; i < numWords; ++i )
187 w[i] = v.w[i];
188 [[maybe_unused]] const auto s = detail::signWord( w[numWords - 1] );
189 for ( int i = numWords; i < FastInt<mBits>::numWords; ++i )
190 assert( v.w[i] == s );
191 }
192
194 [[nodiscard]] constexpr int sign() const noexcept
195 {
196 if ( std::int64_t( w[numWords - 1] ) < 0 )
197 return -1;
198 std::uint64_t any = 0;
199 for ( int i = 0; i < numWords; ++i )
200 any |= w[i];
201 return any != 0 ? 1 : 0;
202 }
203
204 constexpr FastInt & operator +=( const FastInt & b ) noexcept
205 {
206 std::uint64_t carry = 0;
207 for ( int i = 0; i < numWords; ++i )
208 w[i] = detail::addCarry64( w[i], b.w[i], carry );
209 return *this;
210 }
211
212 constexpr FastInt & operator -=( const FastInt & b ) noexcept
213 {
214 std::uint64_t borrow = 0;
215 for ( int i = 0; i < numWords; ++i )
216 w[i] = detail::subBorrow64( w[i], b.w[i], borrow );
217 return *this;
218 }
219
220 [[nodiscard]] constexpr FastInt operator -() const noexcept
221 {
222 FastInt res;
223 res -= *this;
224 return res;
225 }
226
227 [[nodiscard]] friend constexpr FastInt operator +( FastInt a, const FastInt & b ) noexcept { a += b; return a; }
228 [[nodiscard]] friend constexpr FastInt operator -( FastInt a, const FastInt & b ) noexcept { a -= b; return a; }
229
230 [[nodiscard]] friend constexpr bool operator ==( const FastInt & a, const FastInt & b ) noexcept { return a.w == b.w; }
231
232 [[nodiscard]] friend constexpr std::strong_ordering operator <=>( const FastInt & a, const FastInt & b ) noexcept
233 {
234 if ( const auto c = std::int64_t( a.w[numWords - 1] ) <=> std::int64_t( b.w[numWords - 1] ); c != std::strong_ordering::equal )
235 return c;
236 for ( int i = numWords - 2; i >= 0; --i )
237 if ( const auto c = a.w[i] <=> b.w[i]; c != std::strong_ordering::equal )
238 return c;
239 return std::strong_ordering::equal;
240 }
241};
242
244template <int nBits>
245[[nodiscard]] MR_BIND_IGNORE inline double toDouble( const FastInt<nBits> & v ) noexcept
246{
248}
249
253
257
258template <int nBits, int mBits>
259[[nodiscard]] MR_BIND_IGNORE constexpr FastInt<nBits + mBits> operator *( const FastInt<nBits> & a, const FastInt<mBits> & b ) noexcept
260{
262 res.w = detail::mulWords( a.w, b.w );
263 return res;
264}
265
266template <int nBits, typename T>
268[[nodiscard]] MR_BIND_IGNORE constexpr FastInt<nBits + detail::cMulBits<T>> operator *( const FastInt<nBits> & a, T b ) noexcept
269{
271 res.w = detail::mulWords( a.w, detail::mulWordsOf( b ) );
272 return res;
273}
274
275template <int nBits, typename T>
277[[nodiscard]] MR_BIND_IGNORE constexpr FastInt<nBits + detail::cMulBits<T>> operator *( T a, const FastInt<nBits> & b ) noexcept
278{
279 return b * a;
280}
281
285{
286public:
287 Int128Mul256() noexcept = default;
288
289 template <typename T>
290 requires detail::cFitsFastInt128<T>
291 constexpr Int128Mul256( T v ) noexcept : v_( v ) { }
292
293 [[nodiscard]] constexpr explicit operator FastInt128() const noexcept { return v_; }
294
295 [[nodiscard]] friend constexpr FastInt128 operator +( Int128Mul256 a ) noexcept { return a.v_; }
296 [[nodiscard]] friend constexpr FastInt128 operator -( Int128Mul256 a ) noexcept { return -a.v_; }
297
298 [[nodiscard]] friend constexpr FastInt128 operator +( Int128Mul256 a, Int128Mul256 b ) noexcept { return a.v_ + b.v_; }
299 [[nodiscard]] friend constexpr FastInt128 operator -( Int128Mul256 a, Int128Mul256 b ) noexcept { return a.v_ - b.v_; }
300 [[nodiscard]] friend constexpr FastInt128 operator /( Int128Mul256 a, Int128Mul256 b ) noexcept { return a.v_ / b.v_; }
301
302 [[nodiscard]] friend constexpr FastInt256 operator *( Int128Mul256 a, Int128Mul256 b ) noexcept
303 {
304 const FastUInt128 ua( a.v_ ), ub( b.v_ );
305 FastInt256 res;
306 res.w = detail::mulWords( std::array{ std::uint64_t( ua ), std::uint64_t( ua >> 64 ) },
307 std::array{ std::uint64_t( ub ), std::uint64_t( ub >> 64 ) } );
308 return res;
309 }
310
311 [[nodiscard]] friend constexpr bool operator ==( Int128Mul256 a, Int128Mul256 b ) noexcept { return a.v_ == b.v_; }
312 [[nodiscard]] friend constexpr auto operator <=>( Int128Mul256 a, Int128Mul256 b ) noexcept { return a.v_ <=> b.v_; }
313
314private:
315 FastInt128 v_;
316};
317
319#if !defined MR_PARSING_FOR_ANY_BINDINGS && !defined MR_COMPILING_ANY_BINDINGS
322#endif
323
325
326}
#define MRMESH_API
Definition MRMeshFwd.h:85
Definition MRFastInt.h:141
constexpr FastInt(const FastInt< mBits > &v) noexcept
Definition MRFastInt.h:184
constexpr int sign() const noexcept
-1, 0 or 1 if the value is negative, zero or positive respectively
Definition MRFastInt.h:194
constexpr FastInt(const FastInt< mBits > &v) noexcept
sign-extends a narrower value of this family
Definition MRFastInt.h:169
FastInt() noexcept=default
std::array< std::uint64_t, numWords > w
Definition MRFastInt.h:149
static constexpr int numWords
Definition MRFastInt.h:146
Int128Mul256() 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/(const Color &b, float a)
Definition MRColor.h:129
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
FastInt< 256 > FastInt256
Definition MRFastInt.h:250
MR_BIND_IGNORE double toDouble(FastInt128 v) noexcept
Definition MRFastInt.h:121
Vector3< Int128Mul256 > Vector3i128mul
Definition MRFastInt.h:321
Vector2< Int128Mul256 > Vector2i128mul
no bindings for the same reason as for Vector3i128fast
Definition MRFastInt.h:320
FastInt< 512 > FastInt512
Definition MRFastInt.h:251
FastInt< 1024 > FastInt1024
Definition MRFastInt.h:252
Definition MRFastInt.h:19
constexpr auto mulWordsOf(T v) noexcept
the words of a multiplier of FastInt, sign-extended if it is signed
Definition MRFastInt.h:100
constexpr std::uint64_t signWord(std::uint64_t hi) noexcept
all ones if the highest bit of the given word is set, and zeros otherwise
Definition MRFastInt.h:45
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
double doubleFromWords(const std::uint64_t *w, int n) noexcept
constexpr int cMulBits
Definition MRFastInt.h:96
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
constexpr std::array< std::uint64_t, n+m > mulWords(const std::array< std::uint64_t, n > &a, const std::array< std::uint64_t, m > &b) noexcept
std::size_t and not int, to be deducible from std::array
Definition MRFastInt.h:53
constexpr bool cFitsFastInt128
the integer types that FastInt128 represents exactly, and which the classes below accept
Definition MRFastInt.h:23
only for bindings generation
Definition MRCameraOrientationPlugin.h:8
Definition MRVector2.h:29
Definition MRVector3.h:33