LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
divexact.c
浏览该文件的文档.
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#include "../../../include/lammp/impl/inlines.h"
17#include "../../../include/lammp/impl/mparam.h"
18#include "../../../include/lammp/impl/tmp_alloc.h"
19#include "../../../include/lammp/lmmpn.h"
20#include "../../../include/lammp/numth.h"
21#include "../../../include/lammp/impl/longlong.h"
22
23
25 lmmp_param_assert(d % 2 == 1);
26 lmmp_param_assert(dinv * d == 1);
27 lmmp_param_assert(nn > 0);
28 lmmp_debug_assert(dst != NULL && np != NULL);
29 mp_limb_t c = 0;
30 mp_limb_t l, s, lo, hi, q;
32 for (i = 0; i < nn - 1; i++) {
33 s = np[i];
34 l = s - c;
35 c = l > s;
36 q = l * dinv;
37 dst[i] = q;
38 _umul64to128_(q, d, &lo, &hi);
39 c += hi;
40 }
41 s = np[i];
42 l = s - c;
43 c = l > s;
44 q = l * dinv;
45 dst[i] = q;
46 lmmp_debug_assert(c == 0);
47}
48
50 lmmp_param_assert(dp[0] % 2 == 1);
51 lmmp_param_assert(nn > 1);
52 lmmp_debug_assert(dst != NULL && np != NULL);
53 mp_limb_t c[2] = {0, 0};
54 mp_limb_t l[2], s[2], q[2], t[4];
56 mp_limb_t d0 = dp[0], d1 = dp[1];
57 mp_limb_t ddinv0 = dinv[0], ddinv1 = dinv[1];
58
59 if (nn % 2 == 0) {
60 for (i = 0; i < nn - 2; i += 2) {
61 s[0] = np[i];
62 s[1] = np[i + 1];
63 _u128sub(l, s, c);
64 c[0] = _u128cmp(s, l) ? 1 : 0;
65 c[1] = 0;
66 _umul128to128_(l[1], l[0], ddinv1, ddinv0, q);
67 dst[i] = q[0];
68 dst[i + 1] = q[1];
69 _umul128to256_(q[1], q[0], d1, d0, t);
70 _u128add(c, c, t + 2);
71 }
72 s[0] = np[i];
73 s[1] = np[i + 1];
74 _u128sub(l, s, c);
75 c[0] = _u128cmp(s, l);
76 _umul128to128_(l[1], l[0], ddinv1, ddinv0, q);
77 dst[i] = q[0];
78 lmmp_debug_assert(c[0] == 0);
79 } else {
80 i = 0;
81 if (nn >= 5) {
82 for (; i < nn - 4; i += 2) {
83 s[0] = np[i];
84 s[1] = np[i + 1];
85 _u128sub(l, s, c);
86 c[0] = _u128cmp(s, l);
87 c[1] = 0;
88 _umul128to128_(l[1], l[0], ddinv1, ddinv0, q);
89 dst[i] = q[0];
90 dst[i + 1] = q[1];
91 _umul128to256_(q[1], q[0], d1, d0, t);
92 _u128add(c, c, t + 2);
93 }
94 }
95 s[0] = np[i];
96 s[1] = np[i + 1];
97 _u128sub(l, s, c);
98 c[0] = _u128cmp(s, l);
99 _umul128to128_(l[1], l[0], ddinv1, ddinv0, q);
100 dst[i] = q[0];
101 dst[i + 1] = q[1];
102 lmmp_debug_assert(c[0] == 0);
103 }
104}
105
106static inline void lmmp_mullo_n_(
110 mp_size_t n,
112) {
113 if (n < MULLO_DC_THRESHOLD) {
115 } else {
117 }
118}
119
120/**
121 * @brief 已知乘积的低位,计算乘积的高位
122 * @param dst 乘积的高位,长度为 n
123 * @param lop 乘积的低位,长度为 n
124 * @param numa 乘数a
125 * @param numb 乘数b
126 * @param n 乘数a和乘数b的 limb 长度
127 * @param tp 临时空间(应需要2*n个limb)
128 * @warning eqsep(dst,tp)
129 */
130static inline void lmmp_mulhi_n_(
131 mp_ptr dst,
135 mp_size_t n,
136 mp_ptr tp
137) {
140 lmmp_copy(dst, tp + n, n);
141 } else {
142 mp_limb_t c;
143 mp_size_t m = lmmp_fft_next_size_((n * 2 + 1) >> 1);
144 lmmp_debug_assert(n * 2 > m && m >= n);
146 c = lmmp_sub_(tp, tp, m, lop, n);
147 if (c != 0)
148 lmmp_dec(tp);
149 if (m == n) {
150 lmmp_copy(dst, tp, n);
151 } else {
152 mp_size_t fn = m - n;
153 mp_size_t sn = n - fn;
154 lmmp_copy(dst, tp + n, fn);
155 lmmp_copy(dst + fn, tp, sn);
156 }
157 }
158}
159
161 mp_ptr dst,
162 mp_srcptr np,
163 mp_size_t nn,
167) {
168 lmmp_param_assert(dst != NULL && np != NULL && dp != NULL);
170 lmmp_param_assert(nn >= dn);
171 lmmp_param_assert((dp[0] & 1) != 0);
172
173 TEMP_DECL;
175 if (dinv == NULL) {
178 }
179
180#define c (tp) // [tp, dn]
181#define l (tp + dn) // [tp + dn, dn]
182#define scratch (tp + 2 * dn) // [tp + 2 * dn, 2*dn]
183
184 mp_size_t i = 0, qn = nn - dn + 1;
186 lmmp_zero(c, dn);
187 if (qn > dn) {
188 for (; i < qn - dn; i += dn) {
189 lmmp_sub_n_(l, np + i, c, dn);
190 ca = lmmp_cmp_(l, np + i, dn) == 1 ? 1 : 0;
191 /*
192 FIXME: 这里的循环中,第二个乘数dinv以及dp,始终保持不变
193 在拥有可以惰性初始化的FFT算法的情况下,可以节省numa的正变换
194 在循环的情况下,这将会有可观的性能提升
195 */
198 //lmmp_mul_n_(scratch, dst + i, dp, dn);
199 if (ca) {
200 lmmp_add_1_(c, scratch + dn, dn, 1);
201 } else {
202 lmmp_copy(c, scratch + dn, dn);
203 }
204 }
205 }
206 lmmp_sub_n_(l, np + i, c, dn);
207 lmmp_mullo_n_(dst + i, l, dinv, qn - i, scratch);
208 TEMP_FREE;
209#undef c
210#undef l
211#undef scratch
212}
213
215 lmmp_param_assert(dst != NULL && np != NULL && dp != NULL);
217 lmmp_param_assert(nn >= dn);
218 lmmp_param_assert((dp[0] & 1) != 0);
219 lmmp_param_assert((dp[0] * dinv) == 1);
220 mp_size_t i;
221 mp_limb_t q;
223 mp_size_t qn = nn - dn + 1;
224 for (i = 0; i < qn; i++) {
225 q = dinv * np[i];
226 hi = lmmp_submul_1_(np + i, dp, dn, q);
227 lmmp_debug_assert(np[i] == 0);
228#if LAMMP_DEBUG_ASSERT_CHECK == 1
229 if (hi && i + dn < nn) {
230 lmmp_dec_1(np + i + dn, hi);
231 } else {
232 lmmp_debug_assert(hi == 0);
233 }
234#else
235 if (hi) {
236 lmmp_dec_1(np + i + dn, hi);
237 }
238#endif
239 dst[i] = q;
240 }
241}
242
244 lmmp_param_assert(dst != NULL && np != NULL && dp != NULL);
246 lmmp_param_assert(nn >= dn);
247 lmmp_param_assert((dp[0] & 1) != 0);
248
249 mp_size_t qn = nn - dn + 1;
251 mp_size_t rn = qn - qn / 2;
252 qn = qn / 2;
253
254 TEMP_DECL;
258 lmmp_mullo_n_(dst, np, dinv, rn, tp);
259 if (qn == 0) {
260 TEMP_FREE;
261 return;
262 }
263
264 lmmp_debug_assert(3 * rn >= qn + rn);
265 lmmp_mul_(tp, dp, qn + rn, dst, rn);
266
267 // 即使存在错位,高位的np也一定可以将其约减去,因此无需进行任何处理
268 lmmp_sub_n_(tp, np + rn, tp + rn, qn);
269 lmmp_mullo_n_(dst + rn, tp, dinv, qn, tp + rn);
270 TEMP_FREE;
271}
272
274 lmmp_param_assert(dst != NULL && np != NULL && dp != NULL);
276 lmmp_param_assert(nn >= dn);
277 lmmp_param_assert((dp[0] & 1) != 0);
278
279 if (dn == 1) {
281 lmmp_divexact_1_(dst, np, nn, dp[0], dinv);
282 } else if (dn == 2) {
283 mp_limb_t dinv[2];
285 lmmp_divexact_2_(dst, np, nn, dp, dinv);
286 } else {
287 mp_size_t qn = nn - dn + 1;
290 TEMP_DECL;
292 lmmp_copy(tp, np, nn);
294 TEMP_FREE;
295 } else if (qn < dn) {
296 TEMP_DECL;
298 if (dst == np) {
299 tp = TALLOC_TYPE(nn, mp_limb_t);
300 lmmp_copy(tp, np, nn);
301 np = tp;
302 }
303 lmmp_divexact_divide_(dst, np, nn, dp, dn);
304 TEMP_FREE;
305 } else {
307 }
308 }
309}
#define l
void lmmp_divexact_1_(mp_ptr dst, mp_srcptr np, mp_size_t nn, mp_limb_t d, mp_limb_t dinv)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition divexact.c:24
#define scratch
static void lmmp_mulhi_n_(mp_ptr dst, mp_srcptr restrict lop, mp_srcptr restrict numa, mp_srcptr restrict numb, mp_size_t n, mp_ptr tp)
已知乘积的低位,计算乘积的高位
Definition divexact.c:130
void lmmp_divexact_divide_(mp_ptr restrict dst, mp_srcptr restrict np, mp_size_t nn, mp_srcptr restrict dp, mp_size_t dn)
Definition divexact.c:243
void lmmp_divexact_2_(mp_ptr dst, mp_srcptr np, mp_size_t nn, mp_srcptr restrict dp, mp_srcptr restrict dinv)
Definition divexact.c:49
void lmmp_divexact_(mp_ptr dst, mp_srcptr np, mp_size_t nn, mp_srcptr restrict dp, mp_size_t dn)
Definition divexact.c:273
#define c
void lmmp_divexact_unbalanced_(mp_ptr dst, mp_srcptr np, mp_size_t nn, mp_srcptr restrict dp, mp_size_t dn, mp_ptr restrict dinv)
Definition divexact.c:160
void lmmp_divexact_basecase_(mp_ptr dst, mp_ptr np, mp_size_t nn, mp_srcptr restrict dp, mp_size_t dn, mp_limb_t dinv)
Definition divexact.c:214
static void lmmp_mullo_n_(mp_ptr restrict dst, mp_srcptr restrict numa, mp_srcptr restrict numb, mp_size_t n, mp_ptr restrict tp)
Definition divexact.c:106
#define lmmp_mul_n_
Definition inlines.h:167
mp_limb_t * mp_ptr
Definition lmmp.h:80
#define lmmp_copy(dst, src, n)
Definition lmmp.h:367
#define lmmp_zero(dst, n)
Definition lmmp.h:369
uint64_t mp_size_t
Definition lmmp.h:77
#define lmmp_debug_assert(x)
Definition lmmp.h:390
const mp_limb_t * mp_srcptr
Definition lmmp.h:81
uint64_t mp_limb_t
Definition lmmp.h:76
#define lmmp_param_assert(x)
Definition lmmp.h:401
void lmmp_mul_mersenne_(mp_ptr dst, mp_size_t rn, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
梅森数模乘法 [dst,rn] = [numa,na]*[numb,nb] mod B^rn-1
Definition mul_fft.c:761
static int lmmp_cmp_(mp_srcptr numa, mp_srcptr numb, mp_size_t n)
大数比较函数(内联)
Definition lmmpn.h:996
#define lmmp_dec(p)
大数减1宏(预期无借位)
Definition lmmpn.h:965
static mp_limb_t lmmp_add_1_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_limb_t x)
大数加单精度数静态内联函数 [dst,na]=[numa,na]+x
Definition lmmpn.h:1103
void lmmp_mullo_dc_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_ptr tp, mp_size_t n)
低位乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
void lmmp_mul_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
不等长大数乘法操作 [dst,na+nb] = [numa,na] * [numb,nb]
mp_size_t lmmp_fft_next_size_(mp_size_t n)
计算满足 >=n 的最小费马/梅森乘法可行尺寸
Definition mul_fft.c:95
static mp_limb_t lmmp_sub_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
大数减法静态内联函数 [dst,na]=[numa,na]-[numb,nb]
Definition lmmpn.h:1064
void lmmp_mullo_fft_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n, mp_ptr scratch)
低位FFT乘法 [dst,n] = [numa,n] * [numb,n] mod B^n
Definition mullo.c:22
#define lmmp_dec_1(p, dec)
大数减指定值宏(预期无借位)
Definition lmmpn.h:977
mp_limb_t lmmp_submul_1_(mp_ptr numa, mp_srcptr numb, mp_size_t n, mp_limb_t b)
大数乘以单limb并累减操作 [numa,n] -= [numb,n] * b
mp_limb_t lmmp_sub_n_(mp_ptr dst, mp_srcptr numa, mp_srcptr numb, mp_size_t n)
无借位的n位减法 [dst,n] = [numa,n] - [numb,n]
Definition sub_n.c:80
#define _u128add(r, x, y)
Definition longlong.h:346
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 _u128sub(r, x, y)
Definition longlong.h:368
#define _u128cmp(x, y)
Definition longlong.h:366
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
#define DIVEXACT_NN_THRESHOLD
Definition mparam.h:126
#define MULHI_MERSENNE_THRESHOLD
Definition mparam.h:121
#define MULLO_DC_THRESHOLD
Definition mparam.h:59
#define DIVEXACT_BASECASE_THRESHOLD
Definition mparam.h:124
#define t
#define numb
#define tp
#define s
#define n
#define lo
ulong lmmp_binvert_ulong_(ulong a)
计算 a 在2^64下的逆元
Definition binvert_1.c:42
void lmmp_binvert_n_dc_(mp_ptr dst, mp_srcptr numa, mp_size_t n, mp_ptr tp)
计算 [numa,n] 在 B^n 下的逆元
void lmmp_binvert_2_(mp_ptr dst, mp_srcptr numa)
计算 [numa,2] 在 B^2 下的逆元
Definition binvert_1.c:56
#define TEMP_DECL
Definition tmp_alloc.h:131
#define TEMP_FREE
Definition tmp_alloc.h:150
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:148