LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
gcd_lehmer.c
浏览该文件的文档.
1/*
2 * LAMMP - Copyright (C) 2025-2026 HJimmyK(Jericho Knox)
3 * This file is part of lammp, under the GNU LGPL v2 license.
4 * See LICENSE in the project root for the full license text.
5 */
6
7#include "../../../include/lammp/lmmpn.h"
8#include "../../../include/lammp/numth.h"
9#include "../../../include/lammp/impl/tmp_alloc.h"
10
11typedef struct {
12 slong m11, m12;
13 slong m21, m22;
15
16#define LEHMER_MIN_V 0x100000000ull
17#define LEHMER_EXACT_BITS 63
18
20#define A (gcd->m11)
21#define B (gcd->m12)
22#define C (gcd->m21)
23#define D (gcd->m22)
24
25 lmmp_debug_assert(u >= 0 && v >= 0);
26 lmmp_debug_assert(u >= v);
27 A = 1; B = 0;
28 C = 0; D = 1;
29
30 while (v != 0) {
31 slong q = u / v;
32 slong t = u % v;
33
34 u = v;
35 v = t;
36
37 t = A - q * C;
38 A = C;
39 C = t;
40 t = B - q * D;
41 B = D;
42 D = t;
43
44 if (v < (slong)LEHMER_MIN_V) break;
45 }
46
47 return;
48#undef A
49#undef B
50#undef C
51#undef D
52}
53
55 lmmp_param_assert(un > 1 && vn > 1);
56 lmmp_param_assert(un >= vn);
57 lmmp_param_assert(up != NULL && vp != NULL);
58 lmmp_param_assert(a != NULL && b != NULL);
59
60 int kz = lmmp_limb_bits_(up[un - 1]);
61 if (kz >= LEHMER_EXACT_BITS) {
62 *a = up[un - 1] >> (kz - LEHMER_EXACT_BITS);
63 if (vn == un)
64 *b = vp[vn - 1] >> (kz - LEHMER_EXACT_BITS);
65 else
66 *b = 0;
67 } else {
68 *a = up[un - 1] << (LEHMER_EXACT_BITS - kz);
69 *a |= up[un - 2] >> (LIMB_BITS - (LEHMER_EXACT_BITS - kz));
70 if (un > vn + 1) {
71 *b = 0;
72 } else if (un == vn + 1) {
73 *b = vp[vn - 1] >> (LIMB_BITS - (LEHMER_EXACT_BITS - kz));
74 } else {
75 *b = vp[vn - 1] << (LEHMER_EXACT_BITS - kz);
76 *b |= vp[vn - 2] >> (LIMB_BITS - (LEHMER_EXACT_BITS - kz));
77 }
78 }
79}
80
89
90/**
91 * @brief / a \ = / A B \ * / a \
92 * \ b / \ C D / \ b /
93 * @warning [a,an] > [b,bn]
94 * @note 不保证返回结果 [a,an] > [b,bn]
95 * @return a和b是否有一个为0
96 */
98#define A (M->m11)
99#define B (M->m12)
100#define C (M->m21)
101#define D (M->m22)
102#define an (*an)
103#define bn (*bn)
104 if (A == 0) {
105 /* / 0 1 \ / a \
106 \ 1 -q / \ b / */
107 lmmp_debug_assert(B == 1 && C == 1 && D < 0);
108 mp_limb_t c = lmmp_mul_1_(ms->tp, b, bn, -D);
109 if (c == 0)
110 ;
111 else {
112 ++bn;
113 (ms->tp)[bn - 1] = c;
114 }
115 if (an > bn) {
116 lmmp_sub_(a, a, an, b, bn);
117 } else if (an == bn) {
118 int cmp = lmmp_cmp_(a, b, an);
119 if (cmp >= 0)
120 lmmp_sub_(a, a, an, b, bn);
121 else
122 lmmp_sub_(a, b, bn, a, an);
123 } else {
124 lmmp_sub_(a, b, bn, a, an);
125 an = bn;
126 }
127 while (a[an - 1] == 0 && an > 0) {
128 --an;
129 }
130 // return b = b
131 // a = a - q * b
132 return an == 0;
133 } else {
134 if (A < 0) {
135 A = -A;
136 D = -D;
137 } else {
138 B = -B;
139 C = -C;
140 }
141 // A * a + B * b
142 mp_limb_t ca = lmmp_mul_1_(ms->tp, a, an, A);
143 if (ca == 0)
144 ms->tn = an;
145 else {
146 ms->tn = an + 1;
147 (ms->tp)[ms->tn - 1] = ca;
148 }
149 ca = lmmp_mul_1_(ms->mp, b, bn, B);
150 if (ca == 0)
151 ms->mn = bn;
152 else {
153 ms->mn = bn + 1;
154 (ms->mp)[ms->mn - 1] = ca;
155 }
156
157 if (ms->tn > ms->mn) {
158 lmmp_sub_(ms->np, ms->tp, ms->tn, ms->mp, ms->mn);
159 ms->nn = ms->tn;
160 } else if (ms->mn > ms->tn) {
161 lmmp_sub_(ms->np, ms->mp, ms->mn, ms->tp, ms->tn);
162 ms->nn = ms->mn;
163 } else {
164 int cmp = lmmp_cmp_(ms->tp, ms->mp, ms->tn);
165 if (cmp >= 0) {
166 lmmp_sub_(ms->np, ms->tp, ms->tn, ms->mp, ms->mn);
167 ms->nn = ms->tn;
168 } else {
169 lmmp_sub_(ms->np, ms->mp, ms->mn, ms->tp, ms->tn);
170 ms->nn = ms->mn;
171 }
172 }
173 while (ms->np[ms->nn - 1] == 0 && ms->nn > 0) {
174 --(ms->nn);
175 }
176
177 // C * a + D * b
178 ca = lmmp_mul_1_(ms->tp, a, an, C);
179 if (ca == 0)
180 ms->tn = an;
181 else {
182 ms->tn = an + 1;
183 (ms->tp)[ms->tn - 1] = ca;
184 }
185 ca = lmmp_mul_1_(ms->mp, b, bn, D);
186 if (ca == 0)
187 ms->mn = bn;
188 else {
189 ms->mn = bn + 1;
190 (ms->mp)[ms->mn - 1] = ca;
191 }
192
193 if (ms->tn > ms->mn) {
194 lmmp_sub_(a, ms->tp, ms->tn, ms->mp, ms->mn);
195 an = ms->tn;
196 } else if (ms->mn > ms->tn) {
197 lmmp_sub_(a, ms->mp, ms->mn, ms->tp, ms->tn);
198 an = ms->mn;
199 } else {
200 int cmp = lmmp_cmp_(ms->tp, ms->mp, ms->tn);
201 if (cmp >= 0) {
202 lmmp_sub_(a, ms->tp, ms->tn, ms->mp, ms->mn);
203 an = ms->tn;
204 } else {
205 lmmp_sub_(a, ms->mp, ms->mn, ms->tp, ms->tn);
206 an = ms->mn;
207 }
208 }
209 while (a[an - 1] == 0 && an > 0) {
210 --an;
211 }
212
213 // now a = C * a + D * b
214 // ms->np = A * a + B * b
215 if (ms->nn > 0) {
216 lmmp_copy(b, ms->np, ms->nn);
217 bn = ms->nn;
218 return an == 0;
219 } else {
220 b[0] = 0;
221 bn = 0;
222 return true;
223 }
224 }
225#undef A
226#undef B
227#undef C
228#undef D
229#undef an
230#undef bn
231}
232
234 lmmp_param_assert(un > 0 && vn > 0);
235 lmmp_param_assert(up != NULL && vp != NULL);
236 lmmp_param_assert(dst != NULL);
237
238 if (un < vn) {
239 LMMP_SWAP(up, vp, mp_srcptr);
240 LMMP_SWAP(un, vn, mp_size_t);
241 } else if (un == vn) {
242 int cmp = lmmp_cmp_(up, vp, un);
243 if (cmp == 0) {
244 lmmp_copy(dst, up, un);
245 return un;
246 } else if (cmp < 0) {
247 LMMP_SWAP(up, vp, mp_srcptr);
248 }
249 }
250 // u > v
251
253 slong x = 0, y = 0;
254
255#define an un
256#define bn vn
258 // [a,an+1] [b,bn+1]
259 // A * a_old may overlow
260 mp_ptr a = BALLOC_TYPE(an + 1, mp_limb_t);
261 mp_ptr b = BALLOC_TYPE(bn + 1, mp_limb_t);
263 mp_ptr temp = BALLOC_TYPE((an + 1) * 3, mp_limb_t);
264 ms.tp = temp;
265 ms.mp = temp + (an + 1);
266 ms.np = temp + (an + 1) * 2;
267
268 lmmp_copy(a, up, an);
269 lmmp_copy(b, vp, bn);
270
271 bool bzero = false;
272 while (bzero == false) {
273 if (an > 1 && bn == 1) {
274 dst[0] = lmmp_gcd_1_(a, an, b[0]);
275 return 1;
276 } else if (an == 1 && bn == 1) {
277 dst[0] = lmmp_gcd_11_(a[0], b[0]);
278 return 1;
279 }
280 // a > b
281 lmmp_lehmer_extract_(a, an, b, bn, &x, &y);
282 lmmp_gcd_lehmer_step_(x, y, &M);
283
284 if (M.m21 == 0) {
285 lmmp_div_(NULL, dst, a, an, b, bn);
286 lmmp_copy(a, b, bn);
287 an = bn;
288 while (dst[bn - 1] == 0 && bn > 0) {
289 --bn;
290 }
291 if (bn == 0)
292 bzero = true;
293 else
294 lmmp_copy(b, dst, bn);
295 } else {
296 bzero = lmmp_lehmer_mul_(a, &an, b, &bn, &M, &ms);
297 if ((an < bn) || (an == bn && lmmp_cmp_(a, b, an) < 0)) {
298 LMMP_SWAP(a, b, mp_ptr);
300 }
301 }
302 }
303 lmmp_copy(dst, a, an);
305 return an;
306#undef an
307#undef bn
308}
mp_size_t mn
Definition gcd_lehmer.c:86
static void lmmp_gcd_lehmer_step_(slong u, slong v, mp_gcd_lehmer_t *gcd)
Definition gcd_lehmer.c:19
#define B
mp_size_t lmmp_gcd_lehmer_(mp_ptr dst, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
计算两个无符号整数的最大公约数(Lehmer算法)
Definition gcd_lehmer.c:233
#define LEHMER_MIN_V
Definition gcd_lehmer.c:16
#define LEHMER_EXACT_BITS
Definition gcd_lehmer.c:17
#define A
static bool lmmp_lehmer_mul_(mp_ptr a, mp_size_t *an, mp_ptr b, mp_size_t *bn, mp_gcd_lehmer_t *M, lehmer_stack_t *ms)
/ a \ = / A B \ * / a \ \ b / \ C D / \ b /
Definition gcd_lehmer.c:97
mp_size_t nn
Definition gcd_lehmer.c:87
#define an
static void lmmp_lehmer_extract_(mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn, slong *a, slong *b)
Definition gcd_lehmer.c:54
#define C
#define bn
mp_size_t tn
Definition gcd_lehmer.c:85
#define D
mp_limb_t * mp_ptr
Definition lmmp.h:215
#define LMMP_SWAP(x, y, type)
Definition lmmp.h:352
#define lmmp_copy(dst, src, n)
Definition lmmp.h:364
uint64_t mp_size_t
Definition lmmp.h:212
#define lmmp_debug_assert(x)
Definition lmmp.h:387
const mp_limb_t * mp_srcptr
Definition lmmp.h:216
uint64_t mp_limb_t
Definition lmmp.h:211
#define LIMB_BITS
Definition lmmp.h:221
#define lmmp_param_assert(x)
Definition lmmp.h:398
static int lmmp_cmp_(mp_srcptr numa, mp_srcptr numb, mp_size_t n)
大数比较函数(内联)
Definition lmmpn.h:1004
int lmmp_limb_bits_(mp_limb_t x)
计算满足 2^k > x 的最小自然数k
Definition tiny.c:11
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:1072
mp_limb_t lmmp_mul_1_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_limb_t x)
大数乘以单limb操作 [dst,na] = [numa,na] * x
void lmmp_div_(mp_ptr dstq, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
大数除法和取模操作
Definition div.c:57
mp_limb_t lmmp_gcd_1_(mp_srcptr up, mp_size_t un, mp_limb_t vlimb)
计算两个无符号整数的最大公约数
Definition gcd_1.c:30
int64_t slong
Definition numth.h:38
mp_limb_t lmmp_gcd_11_(mp_limb_t u, mp_limb_t v)
计算 [numa,na] 在B^n 下的逆元
Definition gcd_1.c:10
#define TEMP_B_DECL
Definition tmp_alloc.h:75
#define BALLOC_TYPE(n, type)
Definition tmp_alloc.h:89
#define TEMP_B_FREE
Definition tmp_alloc.h:100