LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
longlong.h
浏览该文件的文档.
1/**
2 * Copyright (C) 2026 HJimmyK(Jericho Knox)
3 *
4 * This file is part of LAMMP.
5 *
6 * LAMMP is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License (LGPL) as published
8 * by the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed WITHOUT ANY WARRANTY.
12 *
13 * See <https://www.gnu.org/licenses/>.
14 */
15
16#ifndef __LAMMP_LONGLONG_H__
17#define __LAMMP_LONGLONG_H__
18
19#ifdef _MSC_VER
20#include <intrin.h>
21#include <immintrin.h>
22#elif defined(USE_ASM) && (defined(__x86_64__)) && (defined(__GNUC__) || defined(__clang__))
23#include <x86intrin.h>
24#endif
25
26#include <stdint.h>
27
28#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
29// cnt = ctz(x)
30// r = x >> cnt
31// assume x is non-zero
32#define ctz_shr_u64(r, x, cnt) \
33 do { \
34 unsigned long long _x_ = (x); \
35 unsigned long _bits_ = 0; \
36 _BitScanForward64(&_bits_, _x_); \
37 cnt = _bits_; \
38 (r) = _x_ >> (cnt); \
39 } while (0)
40// cnt = clz(x)
41// r = x << cnt
42// assume x is non-zero
43#define clz_shl_u64(r, x, cnt) \
44 do { \
45 unsigned long long _x_ = (x); \
46 unsigned long _idx_; \
47 _BitScanReverse64(&_idx_, _x_); \
48 (cnt) = 63 - (int)_idx_; \
49 (r) = (unsigned long long)(_x_ << (cnt)); \
50 } while (0)
51#elif defined(__GNUC__) || defined(__clang__)
52// cnt = ctz(x)
53// r = x >> cnt
54// assume x is non-zero
55#define ctz_shr_u64(r, x, cnt) \
56 do { \
57 unsigned long long _x_ = (x); \
58 (cnt) = __builtin_ctzll(_x_); \
59 (r) = _x_ >> (cnt); \
60 } while (0)
61// cnt = clz(x)
62// r = x << cnt
63// assume x is non-zero
64#define clz_shl_u64(r, x, cnt) \
65 do { \
66 unsigned long long _x_ = (x); \
67 (cnt) = __builtin_clzll(_x_); \
68 (r) = (unsigned long long)(_x_ << (cnt)); \
69 } while (0)
70#else
71// cnt = ctz(x)
72// r = x >> cnt
73// assume x is non-zero
74#define ctz_shr_u64(r, x, cnt) \
75 do { \
76 uint64_t _x_ = (x); \
77 int _i_ = 0; \
78 while ((_x_ & 1) == 0) { \
79 _i_++; \
80 _x_ >>= 1; \
81 } \
82 cnt = _i_; \
83 (r) = _x_; \
84 } while (0)
85// cnt = clz(x)
86// r = x << cnt
87// assume x is non-zero
88#define clz_shl_u64(r, x, cnt) \
89 do { \
90 uint64_t _x_ = (x); \
91 int _c_ = 0; \
92 while ((_x_ & 0x8000000000000000ULL) == 0) { \
93 _c_++; \
94 _x_ <<= 1; \
95 } \
96 (cnt) = _c_; \
97 (r) = _x_; \
98 } while (0)
99#endif
100
101#if defined(_MSC_VER)
102// cnt = ctz(x)
103// r = x >> cnt
104// assume x is non-zero
105#define ctz_shr_u32(r, x, cnt) \
106 do { \
107 unsigned long _x_ = (x); \
108 unsigned long _bits_ = 0; \
109 _BitScanForward(&_bits_, _x_); \
110 cnt = _bits_; \
111 (r) = _x_ >> (cnt); \
112 } while (0)
113// cnt = clz(x)
114// r = x << cnt
115// assume x is non-zero
116#define clz_shl_u32(r, x, cnt) \
117 do { \
118 unsigned long _x_ = (x); \
119 unsigned long _idx_; \
120 _BitScanReverse(&_idx_, _x_); \
121 (cnt) = 31 - (int)_idx_; \
122 (r) = _x_ << (cnt); \
123 } while (0)
124#elif defined(__GNUC__) || defined(__clang__)
125// cnt = ctz(x)
126// r = x >> cnt
127// assume x is non-zero
128#define ctz_shr_u32(r, x, cnt) \
129 do { \
130 unsigned int _x_ = (x); \
131 (cnt) = __builtin_ctz(_x_); \
132 (r) = _x_ >> (cnt); \
133 } while (0)
134// cnt = clz(x)
135// r = x << cnt
136// assume x is non-zero
137#define clz_shl_u32(r, x, cnt) \
138 do { \
139 unsigned int _x_ = (x); \
140 (cnt) = __builtin_clz(_x_); \
141 (r) = _x_ << (cnt); \
142 } while (0)
143#else
144// cnt = ctz(x)
145// r = x >> cnt
146// assume x is non-zero
147#define ctz_shr_u32(r, x, cnt) \
148 do { \
149 uint32_t _x_ = (x); \
150 int _i_ = 0; \
151 while ((_x_ & 1U) == 0) { \
152 _i_++; \
153 _x_ >>= 1; \
154 } \
155 cnt = _i_; \
156 (r) = _x_; \
157 } while (0)
158// cnt = clz(x)
159// r = x << cnt
160// assume x is non-zero
161#define clz_shl_u32(r, x, cnt) \
162 do { \
163 uint32_t _x_ = (x); \
164 int _c_ = 0; \
165 while ((_x_ & 0x80000000U) == 0) { \
166 _c_++; \
167 _x_ <<= 1; \
168 } \
169 (cnt) = _c_; \
170 (r) = _x_; \
171 } while (0)
172#endif
173
174static inline void _umul64to128_(uint64_t a, uint64_t b, uint64_t *low, uint64_t *high) {
175#if (defined(__GNUC__) || defined(__clang__))
176 __uint128_t prod = (__uint128_t)a * b;
177 *low = (uint64_t)prod;
178 *high = (uint64_t)(prod >> 64);
179#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
180 *low = _umul128(a, b, high);
181#else
182 uint64_t ah = a >> 32, bh = b >> 32;
183 a = (uint32_t)a, b = (uint32_t)b;
184 uint64_t r0 = a * b, r1 = a * bh, r2 = ah * b, r3 = ah * bh;
185 r3 += (r1 >> 32) + (r2 >> 32);
186 r1 = (uint32_t)r1, r2 = (uint32_t)r2;
187 r1 += r2;
188 r1 += (r0 >> 32);
189 *high = r3 + (r1 >> 32);
190 *low = (r1 << 32) | (uint32_t)r0;
191#endif
192}
193
194static inline uint64_t _umul64to64hi_(uint64_t a, uint64_t b) {
195#if (defined(__GNUC__) || defined(__clang__)) && defined(__SIZEOF_INT128__)
196 __uint128_t t = (__uint128_t)a * (__uint128_t)b;
197 return (uint64_t)(t >> 64);
198#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
199 return __umulh(a, b);
200#else
201 uint64_t ah = a >> 32, bh = b >> 32;
202 a = (uint32_t)a, b = (uint32_t)b;
203 uint64_t r0 = a * b, r1 = a * bh, r2 = ah * b, r3 = ah * bh;
204 r3 += (r1 >> 32) + (r2 >> 32);
205 r1 = (uint32_t)r1, r2 = (uint32_t)r2;
206 r1 += r2;
207 r1 += (r0 >> 32);
208 return r3 + (r1 >> 32);
209#endif
210}
211
212static inline void _umul128to256_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[4]) {
213 uint64_t p1_low, p1_high; // p1 = a_low × b_high
214 uint64_t p2_low, p2_high; // p2 = a_high × b_low
215 _umul64to128_(a_low, b_low, rr, rr + 1);
216 _umul64to128_(a_low, b_high, &p1_low, &p1_high);
217 _umul64to128_(a_high, b_low, &p2_low, &p2_high);
218 _umul64to128_(a_high, b_high, rr + 2, rr + 3);
219 /*
220 | res0 | res1 | res2 | res3 |
221 | p0l | p0h | | |
222 | p1l | p1h | |
223 | p2l | p2h | |
224 | | p3l | p3h |
225 */
226 rr[1] += p1_low;
227 uint64_t carry = (rr[1] < p1_low) ? 1 : 0;
228 rr[1] += p2_low;
229 carry += (rr[1] < p2_low) ? 1 : 0;
230
231 rr[2] += carry;
232 carry = (rr[2] < carry) ? 1 : 0;
233 rr[2] += p1_high;
234 carry += (rr[2] < p1_high) ? 1 : 0;
235 rr[2] += p2_high;
236 carry += (rr[2] < p2_high) ? 1 : 0;
237
238 rr[3] += carry;
239}
240
241static inline void _umul128to128_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[2]) {
242 _umul64to128_(a_low, b_low, rr, rr + 1);
243 rr[1] += a_low * b_high;
244 rr[1] += a_high * b_low;
245}
246
247static inline uint64_t _udiv128by64to64_(uint64_t numhi, uint64_t numlo, uint64_t den, uint64_t* r) {
248#if (defined(__GNUC__) || defined(__clang__)) && defined(USE_ASM)
249 uint64_t result;
250 __asm__("div %[v]" : "=a"(result), "=d"(*r) : [v] "r"(den), "a"(numlo), "d"(numhi));
251 return result;
252#elif defined(__GNUC__)
253 __uint128_t num = (__uint128_t)numhi << 64 | numlo;
254 uint64_t result = num / den;
255 *r = num % den;
256 return result;
257#elif defined(_MSC_VER) && (defined(_M_X64)) && (!defined(__clang__))
258 return _udiv128(numhi, numlo, den, r);
259#else
260 const uint64_t b = ((uint64_t)1 << 32);
261
262 uint32_t q1;
263 uint32_t q0;
264
265 uint64_t q;
266
267 int shift;
268
269 uint64_t den10 = den;
270 uint64_t num10 = numlo;
271
272 uint32_t den1;
273 uint32_t den0;
274 uint32_t num1;
275 uint32_t num0;
276
277 uint64_t rem;
278
279 uint64_t qhat;
280 uint64_t rhat;
281
282 uint64_t c1;
283 uint64_t c2;
284
285 if (numhi >= den) {
286 if (r)
287 *r = ~0ull;
288 return ~0ull;
289 }
290
291 clz_shl_u64(den, den, shift);
292 numhi <<= shift;
293 numhi |= (numlo >> (-shift & 63)) & (uint64_t)(-(int64_t)shift >> 63);
294 numlo <<= shift;
295
296 num1 = (uint32_t)(numlo >> 32);
297 num0 = (uint32_t)(numlo & 0xFFFFFFFFu);
298 den1 = (uint32_t)(den >> 32);
299 den0 = (uint32_t)(den & 0xFFFFFFFFu);
300
301 qhat = numhi / den1;
302 rhat = numhi % den1;
303 c1 = qhat * den0;
304 c2 = rhat * b + num1;
305 if (c1 > c2)
306 qhat -= (c1 - c2 > den) ? 2 : 1;
307 q1 = (uint32_t)qhat;
308
309 rem = numhi * b + num1 - q1 * den;
310
311 qhat = rem / den1;
312 rhat = rem % den1;
313 c1 = qhat * den0;
314 c2 = rhat * b + num0;
315 if (c1 > c2)
316 qhat -= (c1 - c2 > den) ? 2 : 1;
317 q0 = (uint32_t)qhat;
318
319 q = ((uint64_t)q1 << 32) | q0;
320
321 if (r)
322 *r = num10 - q * den10;
323 return q;
324#endif
325}
326
327typedef uint64_t u128[2];
328typedef uint64_t u192[3];
329
330#define _u128lshl(x, y, n) \
331 do { \
332 (*((x) + 1)) = ((*(y)) >> (64 - (n))) | ((*((y) + 1)) << (n)); \
333 (*(x)) = (*(y)) << (n); \
334 } while (0)
335
336#define _u128lshr(x, y, n) \
337 do { \
338 (*(x)) = ((*(y)) >> (n)) | ((*((y) + 1)) << (64 - (n))); \
339 (*((x) + 1)) = (*((y) + 1)) >> (n); \
340 } while (0)
341
342#define _u128high(x) (*((x) + 1))
343
344#define _u128low(x) (*(x))
345
346#define _u128add(r, x, y) \
347 do { \
348 (*(r)) = *(x) + *(y); \
349 (*((r) + 1)) = (*((x) + 1)) + (*((y) + 1)) + ((*(r)) < (*(y)) ? 1 : 0); \
350 } while (0)
351
352#define _u128add64(r, x, _i64) \
353 do { \
354 (*(r)) = *(x) + (_i64); \
355 (*((r) + 1)) = (*((x) + 1)) + (((*(r)) < (_i64)) ? 1 : 0); \
356 } while (0)
357
358#define _u128sub64(r, x, _i64) \
359 do { \
360 uint64_t _c_ = (x)[0] < (_i64); \
361 (r)[0] = (x)[0] - (_i64); \
362 (r)[1] = (x)[1] - _c_; \
363 } while (0)
364
365// true if x < y, false otherwise
366#define _u128cmp(x, y) ((x)[1] < (y)[1] || ((x)[1] == (y)[1] && (x)[0] < (y)[0]))
367
368#define _u128sub(r, x, y) \
369 do { \
370 uint64_t _c_ = (x)[0] < (y)[0]; \
371 (r)[0] = (x)[0] - (y)[0]; \
372 (r)[1] = (x)[1] - (y)[1] - _c_; \
373 } while (0)
374
375#define _u128mul(r, x, y) _umul64to128_((x), (y), (r), (((r) + 1)))
376
377#define _u192add(i192, j192) \
378 do { \
379 (i192)[0] += (j192)[0]; \
380 uint64_t _c_ = ((i192)[0] < (j192)[0]) ? 1 : 0; \
381 (i192)[1] += _c_; \
382 _c_ = ((i192)[1] < _c_) ? 1 : 0; \
383 (i192)[1] += (j192)[1]; \
384 _c_ += ((i192)[1] < (j192)[1]) ? 1 : 0; \
385 (i192)[2] += _c_ + (j192)[2]; \
386 } while (0)
387
388#define _u192sub(i192, j192) \
389 do { \
390 uint64_t _b_ = ((i192)[0] < (j192)[0]) ? 1 : 0; \
391 (i192)[0] -= (j192)[0]; \
392 uint64_t _b1_ = ((i192)[1] < (j192)[1]) ? 1 : 0; \
393 (i192)[1] -= (j192)[1]; \
394 _b1_ += ((i192)[1] < _b_) ? 1 : 0; \
395 (i192)[1] -= _b_; \
396 (i192)[2] = (i192)[2] - ((j192)[2] + _b1_); \
397 } while (0)
398
399#define _add_ssaaaa(sh, sl, ah, al, bh, bl) \
400 do { \
401 uint64_t _x_; \
402 _x_ = (al) + (bl); \
403 (sh) = (ah) + (bh) + (_x_ < (al)); \
404 (sl) = _x_; \
405 } while (0)
406
407#define _sub_ddmmss(sh, sl, ah, al, bh, bl) \
408 do { \
409 uint64_t _x_; \
410 _x_ = (al) - (bl); \
411 (sh) = (ah) - (bh) - ((al) < (bl)); \
412 (sl) = _x_; \
413 } while (0)
414
415#define _udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
416 do { \
417 uint64_t _qh_, _ql_, _r_, _mask_; \
418 _umul64to128_((nh), (di), &_ql_, &_qh_); \
419 _add_ssaaaa(_qh_, _ql_, _qh_, _ql_, (nh) + 1, (nl)); \
420 _r_ = (nl) - _qh_ * (d); \
421 _mask_ = -(mp_limb_t)(_r_ > _ql_); \
422 _qh_ += _mask_; \
423 _r_ += _mask_ & (d); \
424 if (_r_ >= (d)) { \
425 _r_ -= (d); \
426 _qh_++; \
427 } \
428 (r) = _r_; \
429 (q) = _qh_; \
430 } while (0)
431
432#define _udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \
433 do { \
434 mp_limb_t _q0_, _t1_, _t0_, _mask_; \
435 _umul64to128_((n2), (dinv), &_q0_, &(q)); \
436 _add_ssaaaa((q), _q0_, (q), _q0_, (n2), (n1)); \
437 /* Compute the two most significant limbs of n - q'd */ \
438 (r1) = (n1) - (d1) * (q); \
439 _sub_ddmmss((r1), (r0), (r1), (n0), (d1), (d0)); \
440 _umul64to128_((d0), (q), &_t0_, &_t1_); \
441 _sub_ddmmss((r1), (r0), (r1), (r0), _t1_, _t0_); \
442 (q)++; \
443 /* Conditionally adjust q and the remainders */ \
444 _mask_ = -(uint64_t)((r1) >= _q0_); \
445 (q) += _mask_; \
446 _add_ssaaaa((r1), (r0), (r1), (r0), _mask_ & (d1), _mask_ & (d0)); \
447 if ((r1) >= (d1)) { \
448 if ((r1) > (d1) || (r0) >= (d0)) { \
449 (q)++; \
450 _sub_ddmmss((r1), (r0), (r1), (r0), (d1), (d0)); \
451 } \
452 } \
453 } while (0)
454
455// q = n0 / d0, assuming d0 is a 32-bit number, d0 > 1
456// dinv = (B-1)//d0 + 1
457#define _udiv32by32_q_preinv(q, n0, dinv) \
458 do { \
459 uint64_t _hi_, _lo_; \
460 _umul64to128_((n0), (dinv), &_lo_, &_hi_); \
461 (q) = _hi_; \
462 } while (0)
463
464/******************************
465from https://libdivide.com/
466******************************/
467
468#define _U64_SHIFT_MASK 0x3F
469#define _ADD_MARKER 0x40
470
471typedef struct _udiv64_t {
472 uint64_t magic;
473 uint8_t more;
475
476// assert d != 0
477static inline _udiv64_t _udiv64_gen_internal_(uint64_t d, int branchfree) {
478 _udiv64_t result;
479 int shift;
480 uint64_t t;
481 clz_shl_u64(t, d, shift);
482 (void)t;
483 uint32_t floor_log_2_d = 63 - shift;
484
485 // Power of 2
486 if ((d & (d - 1)) == 0) {
487 // We need to subtract 1 from the shift value in case of an unsigned
488 // branchfree divider because there is a hardcoded right shift by 1
489 // in its division algorithm. Because of this we also need to add back
490 // 1 in its recovery algorithm.
491 result.magic = 0;
492 result.more = (uint8_t)(floor_log_2_d - (branchfree != 0));
493 } else {
494 uint64_t proposed_m, rem;
495 uint8_t more;
496 // (1 << (64 + floor_log_2_d)) / d
497 proposed_m = _udiv128by64to64_((uint64_t)1 << floor_log_2_d, 0, d, &rem);
498
499 const uint64_t e = d - rem;
500
501 // This power works if e < 2**floor_log_2_d.
502 if (!branchfree && e < ((uint64_t)1 << floor_log_2_d)) {
503 // This power works
504 more = (uint8_t)floor_log_2_d;
505 } else {
506 // We have to use the general 65-bit algorithm. We need to compute
507 // (2**power) / d. However, we already have (2**(power-1))/d and
508 // its remainder. By doubling both, and then correcting the
509 // remainder, we can compute the larger division.
510 // don't care about overflow here - in fact, we expect it
511 proposed_m += proposed_m;
512 const uint64_t twice_rem = rem + rem;
513 if (twice_rem >= d || twice_rem < rem)
514 proposed_m += 1;
515 more = (uint8_t)(floor_log_2_d | _ADD_MARKER);
516 }
517 result.magic = 1 + proposed_m;
518 result.more = more;
519 // result.more's shift should in general be ceil_log_2_d. But if we
520 // used the smaller power, we subtract one from the shift because we're
521 // using the smaller power. If we're using the larger power, we
522 // subtract one from the shift because it's taken care of by the add
523 // indicator. So floor_log_2_d happens to be correct in both cases,
524 // which is why we do it outside of the if statement.
525 }
526 return result;
527}
528
529// d > 1
530static inline _udiv64_t _udiv64_gen(uint64_t d) {
532 _udiv64_t ret = {tmp.magic, (uint8_t)(tmp.more & _U64_SHIFT_MASK)};
533 return ret;
534}
535
536static inline uint64_t _udiv64by64_q_preinv(uint64_t numer, const _udiv64_t* denom) {
537 uint64_t q = _umul64to64hi_(numer, denom->magic);
538 uint64_t t = ((numer - q) >> 1) + q;
539 return t >> denom->more;
540}
541
542#endif // __LAMMP_LONGLONG_H__
uint8_t more
Definition longlong.h:473
static uint64_t _umul64to64hi_(uint64_t a, uint64_t b)
Definition longlong.h:194
uint64_t u192[3]
Definition longlong.h:328
#define _U64_SHIFT_MASK
from https://libdivide.com/
Definition longlong.h:468
static _udiv64_t _udiv64_gen_internal_(uint64_t d, int branchfree)
Definition longlong.h:477
static void _umul64to128_(uint64_t a, uint64_t b, uint64_t *low, uint64_t *high)
Definition longlong.h:174
static void _umul128to256_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[4])
Definition longlong.h:212
#define _ADD_MARKER
Definition longlong.h:469
static _udiv64_t _udiv64_gen(uint64_t d)
Definition longlong.h:530
static void _umul128to128_(uint64_t a_high, uint64_t a_low, uint64_t b_high, uint64_t b_low, uint64_t rr[2])
Definition longlong.h:241
static uint64_t _udiv64by64_q_preinv(uint64_t numer, const _udiv64_t *denom)
Definition longlong.h:536
static uint64_t _udiv128by64to64_(uint64_t numhi, uint64_t numlo, uint64_t den, uint64_t *r)
Definition longlong.h:247
uint64_t u128[2]
Definition longlong.h:327
#define clz_shl_u64(r, x, cnt)
Definition longlong.h:88
uint64_t magic
Definition longlong.h:472
#define r2
#define r1
#define r3
#define r0
#define t
#define tmp
#define c1