LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
is_prime_ulong.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/impl/is_prime_table.h"
8#include "../../../include/lammp/impl/prime_table.h"
9#include "../../../include/lammp/impl/longlong.h"
10#include "../../../include/lammp/impl/mparam.h"
11#include "../../../include/lammp/lmmpn.h"
12#include "../../../include/lammp/numth.h"
13
14/*
15mont63 只能用于小于 2^63 的数,否则会溢出导致计算结果不正确
16mont64 可以用于任意大小的数,但由于考虑了溢出的情况,所以速度理论上会慢一些(并未详细测试)
17*/
18#define MONT63_MAX ((ulong)(0x7fffffffffffffff))
19
20static inline ulong mont64_reduce(u128 t, ulong m, ulong m_inv) {
21 ulong k = t[0] * m_inv;
22 u192 tmp;
23 _u128mul(tmp, k, m);
24 tmp[0] += t[0];
25 ulong c = tmp[0] < t[0];
26 tmp[1] += c;
27 c = tmp[1] == 0;
28 tmp[1] += t[1];
29 c = tmp[1] < t[1];
30 tmp[2] = c;
31 if (!c) {
32 ulong res = tmp[1] >= m ? tmp[1] - m : tmp[1];
33 return res;
34 } else {
35 _u128sub64(tmp + 1, tmp + 1, m);
36 return tmp[1];
37 }
38}
39
40static inline ulong mont64_R2(ulong m) {
41 u192 r = {0, 0, 1};
42 u128 q;
43 lmmp_div_1_s_(q, r, 3, m);
44 return r[0];
45}
46
47static inline ulong to_mont64(ulong x, ulong R2, ulong m, ulong m_inv) {
48 u128 t;
49 _u128mul(t, x, R2);
50 return mont64_reduce(t, m, m_inv);
51}
52
53static inline ulong from_mont64(ulong x, ulong m, ulong m_inv) {
54 u128 t = {x, 0};
55 return mont64_reduce(t, m, m_inv);
56}
57
58static inline ulong mont64_mul(ulong a, ulong b, ulong m, ulong m_inv) {
59 u128 t;
60 _u128mul(t, a, b);
61 return mont64_reduce(t, m, m_inv);
62}
63
64static inline ulong mont63_reduce(u128 t, ulong m, ulong m_inv) {
65 ulong k = t[0] * m_inv;
66 u128 tmp;
67 _u128mul(tmp, k, m);
68 _u128add(tmp, tmp, t);
69 ulong res = tmp[1] >= m ? tmp[1] - m : tmp[1];
70 return res;
71}
72
73static inline ulong mont63_R2(ulong m) {
74 int shift = lmmp_leading_zeros_(m);
75 u192 r = {0, 0, 1ull << shift};
76 u128 q;
77 lmmp_div_1_s_(q, r, 3, m << shift);
78 return r[0] >> shift;
79}
80
81static inline ulong to_mont63(ulong x, ulong R2, ulong m, ulong m_inv) {
82 u128 t;
83 _u128mul(t, x, R2);
84 return mont63_reduce(t, m, m_inv);
85}
86
87static inline ulong from_mont63(ulong x, ulong m, ulong m_inv) {
88 u128 t = {x, 0};
89 return mont63_reduce(t, m, m_inv);
90}
91
92static inline ulong mont63_mul(ulong a, ulong b, ulong m, ulong m_inv) {
93 u128 t;
94 _u128mul(t, a, b);
95 return mont63_reduce(t, m, m_inv);
96}
97
99 lmmp_param_assert(mod > base);
100 lmmp_param_assert(mod > 1);
101 ulong dst = 1;
102 ulong b = base;
103 _udiv64_t binv = _udiv64_gen(mod);
104 ulong q;
105 while (1) {
106 if (exp & 1) {
107 dst *= b;
108 q = _udiv64by64_q_preinv(dst, &binv);
109 dst -= q * mod;
110 }
111 exp >>= 1;
112 if (exp == 0)
113 break;
114 b *= b;
115 q = _udiv64by64_q_preinv(b, &binv);
116 b -= q * mod;
117 }
118 return dst;
119}
120
122 if (mod <= MP_UINT_MAX)
123 return lmmp_powmod_uint_(base, exp, mod);
124 else if (mod <= MONT63_MAX) {
125 ulong R2 = mont63_R2(mod);
126 ulong m_inv = lmmp_binvert_ulong_(mod);
127 m_inv = -m_inv;
128 ulong dst = to_mont63(1, R2, mod, m_inv);
129 base = to_mont63(base, R2, mod, m_inv);
130 while (1) {
131 if (exp & 1)
132 dst = mont63_mul(dst, base, mod, m_inv);
133 exp >>= 1;
134 if (exp == 0)
135 break;
136 base = mont63_mul(base, base, mod, m_inv);
137 }
138 return from_mont63(dst, mod, m_inv);
139 } else {
140 ulong R2 = mont64_R2(mod);
141 ulong m_inv = lmmp_binvert_ulong_(mod);
142 m_inv = -m_inv;
143 ulong dst = to_mont64(1, R2, mod, m_inv);
144 base = to_mont64(base, R2, mod, m_inv);
145 while (1) {
146 if (exp & 1)
147 dst = mont64_mul(dst, base, mod, m_inv);
148 exp >>= 1;
149 if (exp == 0)
150 break;
151 base = mont64_mul(base, base, mod, m_inv);
152 }
153 return from_mont64(dst, mod, m_inv);
154 }
155}
156
157static inline int miller_rabin_32(ulong a, ulong t, ulong u, uint m, _udiv64_t* binv) {
158 ulong v = 1;
159 ulong base = a;
160 ulong q;
161 while (1) {
162 if (u & 1) {
163 v *= base;
164 q = _udiv64by64_q_preinv(v, binv);
165 v -= q * m;
166 }
167 u >>= 1;
168 if (u == 0)
169 break;
170 base *= base;
171 q = _udiv64by64_q_preinv(base, binv);
172 base -= q * m;
173 }
174
175 if (v == 1 || v == m - 1)
176 return 1;
177 for (ulong j = 1; j < t; ++j) {
178 v *= v;
179 q = _udiv64by64_q_preinv(v, binv);
180 v -= q * m;
181 if (v == m - 1)
182 return 1;
183 if (v == 1)
184 return 0;
185 }
186 return 0;
187}
188
189static inline int miller_rabin_63(ulong a, ulong t, ulong u, ulong m, ulong m_inv, ulong one, ulong m_1) {
190 ulong v = one;
191 ulong base = a;
192 while (1) {
193 if (u & 1)
194 v = mont63_mul(v, base, m, m_inv);
195 u >>= 1;
196 if (u == 0)
197 break;
198 base = mont63_mul(base, base, m, m_inv);
199 }
200 if (v == one || v == m_1)
201 return 1;
202
203 for (ulong j = 1; j < t; ++j) {
204 v = mont63_mul(v, v, m, m_inv);
205 if (v == m_1)
206 return 1;
207 if (v == one)
208 return 0;
209 }
210 return 0;
211}
212
213static inline int miller_rabin_64(ulong a, ulong t, ulong u, ulong m, ulong m_inv, ulong one, ulong m_1) {
214 ulong v = one;
215 ulong base = a;
216 while (1) {
217 if (u & 1)
218 v = mont64_mul(v, base, m, m_inv);
219 u >>= 1;
220 if (u == 0)
221 break;
222 base = mont64_mul(base, base, m, m_inv);
223 }
224 if (v == one || v == m_1)
225 return 1;
226 for (ulong j = 1; j < t; ++j) {
227 v = mont64_mul(v, v, m, m_inv);
228 if (v == m_1)
229 return 1;
230 if (v == one)
231 return 0;
232 }
233 return 0;
234}
235
236/*******************************************************************************
237 * from http://probableprime.org/download/example-primality.c
238 * Deterministic Miller-Rabin tests for 64-bit.
239 * Hashed 2-bases for n < 684630005672341 (slightly more than 2^49)
240 * Hashed 3-bases for n < 2^64
241 *
242 * Based on Steve Worley's 2^32 example:
243 * http://www.mersenneforum.org/showthread.php?t=12209
244 * With a 3-base encoding idea from Bradley Berg.
245 *
246 * Copyright 2014, Dana Jacobsen <dana@acm.org>
247 *******************************************************************************/
248
250 if (n < PRIME_SHORT_TABLE_N) {
251 return lmmp_is_prime_table_(n);
252 }
253 if (n % 2 == 0)
254 return false;
255 if (trial_div35711(n))
256 return false;
257 ushort bases[2];
258 bases[0] = 2;
259 bases[1] = dj_base49[((0x3AC69A35UL * n) & 0xFFFFFFFFUL) >> 21] + 3;
260 if (n % bases[0] == 0)
261 return false;
262 if (n % bases[1] == 0)
263 return false;
264
265 ulong u = n - 1, t = 0;
266 while (u % 2 == 0) u /= 2, ++t;
267
268 _udiv64_t binv = _udiv64_gen(n);
269 if (miller_rabin_32(bases[0], t, u, n, &binv))
270 if (miller_rabin_32(bases[1], t, u, n, &binv))
271 return true;
272 else
273 return false;
274 else
275 return false;
276}
277
279 if (n < 684630005672341) {
280 ushort bases[2];
281 bases[0] = 2;
282 bases[1] = dj_base49[((0x3AC69A35UL * n) & 0xFFFFFFFFUL) >> 21] + 3;
283 if (n % bases[0] == 0)
284 return false;
285 if (n % bases[1] == 0)
286 return false;
287
288 ulong one = 1;
289 ulong m_1 = n - 1;
290 ulong m_inv = lmmp_binvert_ulong_(n);
291 m_inv = -m_inv;
292 ulong R2 = mont63_R2(n);
293 one = to_mont63(one, R2, n, m_inv);
294 m_1 = to_mont63(m_1, R2, n, m_inv);
295
296 ulong u = n - 1, t = 0;
297 while (u % 2 == 0) u /= 2, ++t;
298
299 if (miller_rabin_63(bases[0], t, u, n, m_inv, one, m_1))
300 if (miller_rabin_63(bases[1], t, u, n, m_inv, one, m_1))
301 return true;
302 else
303 return false;
304 else
305 return false;
306 } else {
307 ushort bases[3];
308 ulong bbmask = dj_base64[((0x3AC69A35UL * n) & 0xFFFFFFFFUL) >> 18];
309 bases[0] = 2;
310 bases[1] = (bbmask & 0x8000) ? 26460 : 9375;
311 bases[2] = (bbmask & 0x7FFF) + 3;
312
313 if (n % bases[0] == 0)
314 return false;
315 if (n % bases[1] == 0)
316 return false;
317 if (n % bases[2] == 0)
318 return false;
319
320 ulong one = 1;
321 ulong m_1 = n - 1;
322 ulong m_inv = lmmp_binvert_ulong_(n);
323 m_inv = -m_inv;
324
325 if (n <= MONT63_MAX) {
326 ulong R2 = mont63_R2(n);
327 one = to_mont63(one, R2, n, m_inv);
328 m_1 = to_mont63(m_1, R2, n, m_inv);
329
330 ulong u = n - 1, t = 0;
331 while (u % 2 == 0) u /= 2, ++t;
332
333 if (miller_rabin_63(bases[0], t, u, n, m_inv, one, m_1))
334 if (miller_rabin_63(bases[1], t, u, n, m_inv, one, m_1))
335 if (miller_rabin_63(bases[2], t, u, n, m_inv, one, m_1))
336 return true;
337 else
338 return false;
339 else
340 return false;
341 else
342 return false;
343 } else {
344 ulong R2 = mont64_R2(n);
345 one = to_mont64(one, R2, n, m_inv);
346 m_1 = to_mont64(m_1, R2, n, m_inv);
347
348 ulong u = n - 1, t = 0;
349 while (u % 2 == 0) u /= 2, ++t;
350
351 if (miller_rabin_64(bases[0], t, u, n, m_inv, one, m_1))
352 if (miller_rabin_64(bases[1], t, u, n, m_inv, one, m_1))
353 if (miller_rabin_64(bases[2], t, u, n, m_inv, one, m_1))
354 return true;
355 else
356 return false;
357 else
358 return false;
359 else
360 return false;
361 }
362 }
363}
364
366 if (n < PRIME_SHORT_TABLE_N) {
367 return lmmp_is_prime_table_(n);
368 }
369 if (n % 2 == 0)
370 return false;
371 if (trial_div35711(n))
372 return false;
373 return lmmp_is_prime_notrial_(n);
374}
375
376static inline bool trial_div13(ulong n) {
377 const _udiv64_t div13 = {.magic = 4256940940086819604ull, .more = 3};
378 ulong q = _udiv64by64_q_preinv(n, &div13);
379 n -= q * 13;
380 return n == 0;
381}
382
383static inline bool trial_div17(ulong n) {
384 const _udiv64_t div17 = {.magic = 16276538888567251426ull, .more = 4};
385 ulong q = _udiv64by64_q_preinv(n, &div17);
386 n -= q * 17;
387 return n == 0;
388}
389
390static inline bool trial_div19(ulong n) {
391 const _udiv64_t div19 = {.magic = 12621456471485482685ull, .more = 4};
392 ulong q = _udiv64by64_q_preinv(n, &div19);
393 n -= q * 19;
394 return n == 0;
395}
396
397static inline bool trial_div23(ulong n) {
398 const _udiv64_t div23 = {.magic = 7218291159277650633ull, .more = 4};
399 ulong q = _udiv64by64_q_preinv(n, &div23);
400 n -= q * 23;
401 return n == 0;
402}
403
404static inline bool trial_div29(ulong n) {
405 const _udiv64_t div29 = {.magic = 1908283869694091547ull, .more = 4};
406 ulong q = _udiv64by64_q_preinv(n, &div29);
407 n -= q * 29;
408 return n == 0;
409}
410
411static inline bool trial_div31(ulong n) {
412 const _udiv64_t div31 = {.magic = 595056260442243601ull, .more = 4};
413 ulong q = _udiv64by64_q_preinv(n, &div31);
414 n -= q * 31;
415 return n == 0;
416}
417static inline bool trial_div37(ulong n) {
418 const _udiv64_t div37 = {.magic = 13461137567301564693ull, .more = 5};
419 ulong q = _udiv64by64_q_preinv(n, &div37);
420 n -= q * 37;
421 return n == 0;
422}
423
424static inline bool trial_div41(ulong n) {
425 const _udiv64_t div41 = {.magic = 10348173504763894809ull, .more = 5};
426 ulong q = _udiv64by64_q_preinv(n, &div41);
427 n -= q * 41;
428 return n == 0;
429}
430
431// 64位内最大的质数
432#define ULONG_PRIME_MAX 0xFFFFFFFFFFFFFFC5ull
433#define ULONG_PRIME_MIN 2
434
437 ushort idx = lmmp_prime_cnt16_(n);
438 return prime_short_table[idx];
439 } else if (n >= ULONG_PRIME_MAX) {
440 return MP_ULONG_MAX;
441 } else {
442 n += (n % 2 == 0) ? 1 : 2;
443 while(1) {
444 if (trial_div35711(n)
445 || trial_div13(n)
446 || trial_div17(n)
447 || trial_div19(n)
448 || trial_div23(n)
449 || trial_div29(n)
450 || trial_div31(n)
451 || trial_div37(n)
452 || trial_div41(n)) {
453 n += 2;
454 } else {
455 if (lmmp_is_prime_notrial_(n)) {
456 return n;
457 } else {
458 n += 2;
459 }
460 }
461 }
462 }
463}
464
466 if (n < ULONG_PRIME_MIN) {
467 return 0;
468 } else if (n < PRIME_SHORT_TABLE_N) {
469 ushort idx = lmmp_prime_cnt16_(n);
470 return prime_short_table[idx - 1];
471 } else {
472 n -= (n % 2 == 0) ? 1 : 0;
473 while (1) {
474 if (trial_div35711(n)
475 || trial_div13(n)
476 || trial_div17(n)
477 || trial_div19(n)
478 || trial_div23(n)
479 || trial_div29(n)
480 || trial_div31(n)
481 || trial_div37(n)
482 || trial_div41(n)) {
483 n -= 2;
484 } else {
485 if (lmmp_is_prime_notrial_(n)) {
486 return n;
487 } else {
488 n -= 2;
489 }
490 }
491 }
492 }
493}
#define k
static const uint16_t dj_base49[2048]
static const uint16_t dj_base64[16384]
static ulong mont63_reduce(u128 t, ulong m, ulong m_inv)
ulong lmmp_prev_prime_ulong_(ulong n)
小于等于n的上一个素数
static bool trial_div31(ulong n)
static ulong mont64_R2(ulong m)
static bool trial_div13(ulong n)
static bool trial_div41(ulong n)
static int miller_rabin_32(ulong a, ulong t, ulong u, uint m, _udiv64_t *binv)
bool lmmp_is_prime_uint_(uint n)
from http://probableprime.org/download/example-primality.c Deterministic Miller-Rabin tests for 64-bi...
#define MONT63_MAX
static ulong to_mont63(ulong x, ulong R2, ulong m, ulong m_inv)
static bool trial_div29(ulong n)
static bool trial_div37(ulong n)
#define ULONG_PRIME_MIN
static ulong mont63_R2(ulong m)
static ulong from_mont64(ulong x, ulong m, ulong m_inv)
static ulong mont63_mul(ulong a, ulong b, ulong m, ulong m_inv)
uint lmmp_powmod_uint_(uint base, ulong exp, uint mod)
计算 base^exp 对 mod 取模
static int miller_rabin_64(ulong a, ulong t, ulong u, ulong m, ulong m_inv, ulong one, ulong m_1)
ulong lmmp_powmod_ulong_(ulong base, ulong exp, ulong mod)
计算 base^exp 对 mod 取模
static ulong mont64_mul(ulong a, ulong b, ulong m, ulong m_inv)
static ulong from_mont63(ulong x, ulong m, ulong m_inv)
static ulong mont64_reduce(u128 t, ulong m, ulong m_inv)
bool lmmp_is_prime_ulong_(ulong n)
判断素数
#define ULONG_PRIME_MAX
static ulong to_mont64(ulong x, ulong R2, ulong m, ulong m_inv)
static bool trial_div19(ulong n)
static bool trial_div23(ulong n)
ulong lmmp_next_prime_ulong_(ulong n)
大于n的下一个素数
static bool lmmp_is_prime_notrial_(ulong n)
static int miller_rabin_63(ulong a, ulong t, ulong u, ulong m, ulong m_inv, ulong one, ulong m_1)
static bool trial_div17(ulong n)
#define lmmp_param_assert(x)
Definition lmmp.h:398
mp_limb_t lmmp_div_1_s_(mp_ptr dstq, mp_ptr numa, mp_size_t na, mp_limb_t x)
单精度数除法(除数为1个limb)
int lmmp_leading_zeros_(mp_limb_t x)
计算一个单精度数(limb)中前导零的个数
Definition tiny.c:35
#define _u128mul(r, x, y)
Definition longlong.h:289
uint64_t u192[3]
Definition longlong.h:242
#define _u128add(r, x, y)
Definition longlong.h:260
static _udiv64_t _udiv64_gen(uint64_t d)
Definition longlong.h:535
static uint64_t _udiv64by64_q_preinv(uint64_t numer, const _udiv64_t *denom)
Definition longlong.h:541
uint64_t u128[2]
请注意,此处的蒙哥马利域的R为2^64,p不可超过2^63-1
Definition longlong.h:241
uint64_t magic
Definition longlong.h:481
#define _u128sub64(r, x, _i64)
Definition longlong.h:272
#define MP_UINT_MAX
Definition mparam.h:139
#define MP_ULONG_MAX
Definition mparam.h:140
ulong lmmp_binvert_ulong_(ulong a)
计算 a 在2^64下的逆元
Definition binvert_1.c:33
uint32_t uint
Definition numth.h:35
uint16_t ushort
Definition numth.h:33
uint64_t ulong
Definition numth.h:36
static int trial_div35711(ulong n)
校验是否能被3,5,7,11整除,能够整除则返回1,否则返回0
#define PRIME_SHORT_TABLE_SIZE
Definition prime_table.h:30
bool lmmp_is_prime_table_(uint p)
根据全局素数表判断一个数是否为素数
#define PRIME_SHORT_TABLE_N
Definition prime_table.h:32
const ushort prime_short_table[6542]
ushort lmmp_prime_cnt16_(ushort n)
计算小于等于 n 的素数数量