LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
factorial_extra.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/ele_mul.h"
17#include "../../../include/lammp/impl/inlines.h"
18#include "../../../include/lammp/impl/lglg.h"
19#include "../../../include/lammp/impl/mparam.h"
20#include "../../../include/lammp/impl/prime_table.h"
21#include "../../../include/lammp/impl/tmp_alloc.h"
22#include "../../../include/lammp/lmmpn.h"
23#include "../../../include/lammp/numth.h"
24
25
26#define MUL(dst, ap, an, bp, bn) \
27 if (an >= bn) \
28 lmmp_mul_(dst, ap, an, bp, bn); \
29 else \
30 lmmp_mul_(dst, bp, bn, ap, an)
31
32// 无分支,尽管可能导致溢出
33#define mul_1(dst, rn, v) \
34 do { \
35 mp_limb_t _c_ = lmmp_mul_1_(dst, dst, rn, v); \
36 dst[rn] = _c_; \
37 rn += _c_ > 0; \
38 } while (0)
39
42 uint k;
43 if (n < 30) {
44 rn = 64;
45 k = n / 2;
46 if (n % 2 == 0) {
48 } else {
49 *bits = 0;
50 }
51 } else {
52 k = n / 2;
53 if (n % 2 == 0) {
54 // n=2k
55 // n! = (2k)! = 2^k * (k!)
56 rn = k + log2_fac_ceil(k);
58 } else {
59 // n=2k+1
60 // n! = (2k+1)! = (2k+1)! / (2k)!! = (2k+1)! / (2^k * (k!))
62 rn -= k + log2_fac_floor(k);
63 *bits = 0;
64 }
65 }
66 rn = (rn + LIMB_BITS - 1) / LIMB_BITS + 2; // more two limbs
67 return rn;
68}
69
70/*
71 N N/2 N
72 +--+ / +--+ \ 2 / +--+ \
73 | | P_i ^ (e_i) = | | | P_i ^ (e_i / 2) | * | | | P_i ^ ( e_i mod 2) |
74 | | \ | | / \ | | /
75 i=0 i=0 i=0
76*/
77
80 lmmp_param_assert(rn > 0 && nfactors > 0);
81 if (nfactors <= FACTORS_MUL_N_THRESHOLD && rn < 20) {
82 // 此处额外校验rn的大小,因为hyper阶乘和super阶乘在阶数较小时,仅有很少的因子,但其指数很大
83 // 为了避免算法退化,此处校验rn,仅对rn较小时进行朴素乘法。
84 dst[0] = 1;
85 rn = 1;
86 mp_limb_t t = 1;
87 for (ushort i = 0; i < nfactors; i++) {
88 ushort f = fac[i].f;
89 uint j = fac[i].j;
90 lmmp_debug_assert(j != 0 && f <= 0xfff);
91#define MAX_T 0xfffffffffffff
92 for (uint e = 0; e < j; e++) {
93 t *= f;
94 if (t > MAX_T) {
95 mul_1(dst, rn, t);
96 t = 1;
97 }
98 }
99 }
100 if (t != 1) {
101 mul_1(dst, rn, t);
102 }
103#undef MAX_T
104 return rn;
105 } else {
106 TEMP_DECL;
109 ulong t = 1;
110 mp_size_t limbn = 0;
111 for (ushort i = 0; i < nfactors; ++i) {
112 ushort f = fac[i].f;
113 uint j = fac[i].j;
114 if (j > 1) {
115 fac[new_nfactors].f = f;
116 fac[new_nfactors++].j = j >> 1;
117 }
118 if (j & 1) {
119 t *= f;
120#define MAX_T 0xffffffffffff
121 if (t > MAX_T) {
122 limbs[limbn++] = t;
123 t = 1;
124 }
125#undef MAX_T
126 }
127 }
128 if (t != 1) {
129 limbs[limbn++] = t;
130 }
131
133 mp_size_t mpn = 0;
134
135 if (new_nfactors > 0) {
136 if (limbn > 0) {
139 mp_size_t tn = ((rn - mpn) >> 1) + 1;
140 // 这里根据mpn的大小估计剩余因子乘积的长度,额外分配两倍的tn,以进行平方。
141 mp_ptr restrict tp = BALLOC_TYPE(3 * tn + 3, mp_limb_t);
143
144 mp_ptr restrict tp2 = tp + tn + 1;
145 lmmp_sqr_(tp2, tp, tn);
146 tn <<= 1;
147 tn -= tp2[tn - 1] == 0;
148 MUL(dst, tp2, tn, mp, mpn);
149 rn = tn + mpn;
150 rn -= dst[rn - 1] == 0;
151 } else {
152 mp_size_t tn = (rn >> 1) + 1;
155 lmmp_sqr_(dst, tp, tn);
156 rn = tn << 1;
157 rn -= dst[rn - 1] == 0;
158 }
159 } else {
161 // 这里不能直接乘入dst,因为dst的大小可能小于limbn,导致溢出
162 if (rn >= limbn) {
164 } else {
166 lmmp_copy(dst, mp, rn);
167 }
168 }
169 TEMP_FREE;
170 return rn;
171 }
172}
173
175 uint e = 0;
176 uint pn = n;
177 ulong inv = MP_ULONG_MAX / p + 1;
178 while (pn > 0) {
180 e += pn;
181 }
182 pn = k;
183 while (pn > 0) {
185 e -= pn;
186 }
187 if (e > 0) {
188 fac[nfactors].f = p;
189 fac[nfactors++].j = e;
190 }
191 return nfactors;
192}
193
194/**
195 * @brief 计算奇数双阶乘(n!!)
196 * @param dst 输出数组
197 * @param rn 输出数组的长度
198 * @param n 奇数,等于2k+1
199 * @param k 双阶乘的参数
200 * @return 输出数组的长度
201 */
218
219/**
220 * @brief 计算奇数双阶乘(n!!)
221 * @param dst 输出数组
222 * @param rn 输出数组的长度
223 * @param n 奇数,等于2k+1
224 * @param k 双阶乘的参数
225 * @return 输出数组的长度
226 */
232 nfactors = 0;
233
236 while (cache.is_end == 0) {
238 for (uint i = 0; i < cache.size; i++) {
239 // 对于阶乘n!,对于所有小于等于n的质数,贡献都至少为1
241 }
242 }
244
246
248 return rn;
249}
250
252 static const mp_limb_t odd_2factorial_table[17] = {1, 3, 15, 105, 945, 10395, 135135,
253 2027025, 34459425, 654729075,
254 13749310575, 316234143225,
255 7905853580625, 213458046676875,
256 6190283353629375, 191898783962510625,
257 6332659870762850625};
258
262 bits %= LIMB_BITS;
263 lmmp_zero(dst, shw);
264
265 uint k = n / 2;
266 if (n % 2 == 0) {
267 if (k <= MP_USHORT_MAX)
269 else
271 } else {
272 if (k < 17) {
274 rn = 1;
275 } else if (n <= MP_USHORT_MAX)
277 else
279 }
280
281 if (bits > 0) {
282 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
283 rn += shw + 1;
284 rn -= dst[rn - 1] == 0;
285 } else {
286 rn += shw;
287 }
288 return rn;
289}
290
292 uint v = 0;
293 uint npi = n / p;
294 uint pi = p;
295 while (npi > 0) {
296 v += pi * npi * (npi + 1) / 2;
297 npi /= p;
298 pi *= p;
299 }
300 return v;
301}
302
304 uint v = 0;
305 uint pi = p;
306 uint N = (uint)n + 1;
307 uint npi = n / pi;
308 while (npi > 0) {
309 v += npi * N - pi * npi * (npi + 1) / 2;
310 pi *= p;
311 npi /= p;
312 }
313 return v;
314}
315
317 if (n == 0 || n == 1) {
318 *bits = 0;
319 return 1;
320 }
321 // A = 1.2824271291006226369 Glaisher–Kinkelin constant
322 const double logA = 0.24875447703378426;
323 const double log2 = 0.69314718055994531; // log(2)
324 double n_sqr = (uint)n * n;
325 double log_n = log(n);
326 double r = 0.5 * n_sqr * log_n - 0.25 * n_sqr + 0.5 * log_n * (double)n + 1.0 / 12.0 * log_n + logA;
328 rn = (rn + LIMB_BITS - 1) / LIMB_BITS + 2; // more two limbs
330 return rn;
331}
332
334 if (n == 0 || n == 1) {
335 *bits = 0;
336 return 1;
337 }
338 // zeta函数在-1处的导数
339 // zeta(-1) = 1/12 - log(A) // A 即 Glaisher–Kinkelin constant
340 const double zeta_diff_neg1 = -0.16542114370045093;
341 const double log2 = 0.69314718055994531; // log(2)
342 const double log_2pi = 1.83787706640934548; // log(2*pi)
343 double z = (double)n + 1;
344 double z_sqr = z * z;
345 double log_z = log(z);
346 double r = 0.5 * z_sqr * log_z - 0.75 * z_sqr + 0.5 * z * log_2pi - 1.0 / 12.0 * log_z + zeta_diff_neg1;
348 rn = (rn + LIMB_BITS - 1) / LIMB_BITS + 2; // more two limbs
350 return rn;
351}
352
356 bits %= LIMB_BITS;
357 if (n == 0) {
359 dst[0] = 1;
360 return 1;
361 } else if (n <= 8) {
363 static const mp_limb_t odd_hyperfac_table[8] = {1, 1, 27, 27, 84375, 61509375, 50655615215625, 50655615215625};
364 dst[0] = odd_hyperfac_table[n - 1];
365 rn = 1;
366 } else {
367 lmmp_zero(dst, shw);
368 TEMP_DECL;
372 nfactors = 0;
373 for (ushort i = 1; i < primen; ++i) {
376 fac[nfactors].f = p;
377 fac[nfactors++].j = j;
378 }
379
382 TEMP_FREE;
383 }
384 if (bits > 0) {
385 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
386 rn += shw + 1;
387 rn -= dst[rn - 1] == 0;
388 } else {
389 rn += shw;
390 }
391 return rn;
392}
393
397 bits %= LIMB_BITS;
398 if (n == 0) {
400 dst[0] = 1;
401 return 1;
402 } else if (n <= 8) {
404 static const mp_limb_t odd_superfac_table[8] = {1, 1, 3, 9, 135, 6075, 1913625, 602791875};
405 dst[0] = odd_superfac_table[n - 1];
406 rn = 1;
407 } else {
408 lmmp_zero(dst, shw);
409 TEMP_DECL;
413 nfactors = 0;
414 for (ushort i = 1; i < primen; ++i) {
417 fac[nfactors].f = p;
418 fac[nfactors++].j = j;
419 }
420
423 TEMP_FREE;
424 }
425 if (bits > 0) {
426 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
427 rn += shw + 1;
428 rn -= dst[rn - 1] == 0;
429 } else {
430 rn += shw;
431 }
432 return rn;
433}
434
436 // Chebyshev's estimate
437 // pn# < exp(1.000028*n)
438 const double log2 = 0.69314718055994531; // log(2)
439 double l = 1.000028 * (double)n;
440 l /= log2;
442 rn = (rn + LIMB_BITS - 1) / LIMB_BITS + 2; // more two limbs
443 return rn;
444}
445
447 if (n < 2) {
448 dst[0] = 1;
449 return 1;
450 } else if (n <= MP_USHORT_MAX) {
453 ulongp restrict pp = SALLOC_TYPE(primen / 4 + 1, ulong);
454 ulong t = 1;
455 mp_size_t pn = 0;
456 for (ushort i = 0; i < primen; i++) {
458#define MAX_T 0xffffffffffff
459 if (t > MAX_T) {
460 pp[pn++] = t;
461 t = 1;
462 }
463#undef MAX_T
464 }
465 if (t > 1) {
466 pp[pn++] = t;
467 }
468
469 if (rn >= pn) {
472 } else {
476 lmmp_copy(dst, prod, pn);
477 }
479 return pn;
480 } else {
484 ulongp restrict pp = BALLOC_TYPE(pn / 2 + 1, ulong);
485 pn = 0;
486 ulong t = 2; // 2 is the smallest prime number
487
490 while (cache.is_end == 0) {
492 for (uint i = 0; i < cache.size; i++) {
493 t *= cache.pp[i];
494 if (t > MP_UINT_MAX) {
495 pp[pn++] = t;
496 t = 1;
497 }
498 }
499 }
501
502 if (t > 1) {
503 pp[pn++] = t;
504 }
505
506 if (rn >= pn) {
509 } else {
513 lmmp_copy(dst, prod, pn);
514 }
515
517 return pn;
518 }
519}
#define k
#define l
mp_size_t lmmp_elem_mul_ulong_(mp_ptr dst, const ulongp limbs, mp_size_t n, mp_ptr tp)
计算limbs数组的累乘积
mp_size_t lmmp_factors_mul_(mp_ptr dst, mp_size_t rn, fac_ptr fac, uint nfactors)
计算因子的累乘,并将结果放入dst中
static uint count_superfac_factors(ushort n, ushort p)
#define MUL(dst, ap, an, bp, bn)
Copyright (C) 2026 HJimmyK(Jericho Knox)
mp_size_t lmmp_factors_mul_ushort_(mp_ptr restrict dst, mp_size_t rn, fac_ptr restrict fac, ushort nfactors)
#define MAX_T
#define mul_1(dst, rn, v)
mp_size_t lmmp_2factorial_size_(uint n, mp_bitcnt_t *restrict bits)
mp_size_t lmmp_superfac_(mp_ptr restrict dst, mp_bitcnt_t bits, mp_size_t rn, ushort n)
static mp_size_t lmmp_odd_2factorial_ushort_(mp_ptr restrict dst, mp_size_t rn, ushort n, ushort k)
计算奇数双阶乘(n!!)
mp_size_t lmmp_primefac_size_(uint n)
计算质数阶乘的 limb 缓冲区长度
mp_size_t lmmp_hyperfac_size_(ushort n, mp_bitcnt_t *restrict bits)
mp_size_t lmmp_superfac_size_(ushort n, mp_bitcnt_t *restrict bits)
mp_size_t lmmp_2factorial_(mp_ptr restrict dst, mp_bitcnt_t bits, mp_size_t rn, uint n)
static mp_size_t lmmp_odd_2factorial_uint_(mp_ptr restrict dst, mp_size_t rn, uint n, uint k)
计算奇数双阶乘(n!!)
mp_size_t lmmp_hyperfac_(mp_ptr restrict dst, mp_bitcnt_t bits, mp_size_t rn, ushort n)
mp_size_t lmmp_primefac_(mp_ptr restrict dst, mp_size_t rn, uint n)
static uint count_hyperfac_factors(ushort n, ushort p)
static uint count_2facodd_factors(fac_ptr fac, uint nfactors, uint n, uint k, uint p)
#define lmmp_sqr_
Definition inlines.h:166
#define lmmp_limb_popcnt_
Definition inlines.h:163
static uint64_t log2_fac_ceil(uint32_t n)
计算 log2(n!)的ceil值
Definition lglg.h:241
static uint64_t log2_fac_floor(uint32_t n)
计算 log2(n!)的floor值
Definition lglg.h:260
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
size_t mp_bitcnt_t
Definition lmmp.h:82
uint64_t mp_size_t
Definition lmmp.h:77
#define lmmp_debug_assert(x)
Definition lmmp.h:390
uint64_t mp_limb_t
Definition lmmp.h:76
#define LIMB_BITS
Definition lmmp.h:86
#define lmmp_param_assert(x)
Definition lmmp.h:401
mp_limb_t lmmp_shl_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_size_t shl)
大数左移操作 [dst,na] = [numa,na]<<shl,dst的低shl位填充0
Definition shl.c:19
#define _udiv32by32_q_preinv(q, n0, dinv)
Definition longlong.h:457
#define FACTORS_MUL_N_THRESHOLD
Definition mparam.h:107
#define MP_UINT_MAX
Definition mparam.h:136
#define MP_USHORT_MAX
Definition mparam.h:135
#define MP_ULONG_MAX
Definition mparam.h:137
#define t
#define tp
#define n
mp_size_t lmmp_odd_factorial_uint_(mp_ptr dst, mp_size_t rn, uint n)
计算 n! 阶乘的奇数部分
mp_size_t lmmp_odd_nPr_ushort_(mp_ptr dst, mp_size_t rn, ulong n, ulong r)
计算 nPr 排列数的奇数部分
uint64_t * ulongp
Definition numth.h:41
uint32_t uint
Definition numth.h:31
uint16_t ushort
Definition numth.h:29
uint64_t ulong
Definition numth.h:32
void lmmp_prime_cache_free_(prime_cache_t *cache)
释放素数表缓存
void lmmp_prime_cache_next_(prime_cache_t *cache)
素数表缓存更新(从小到大遍历全局质数表)
static ulong lmmp_prime_size_(ulong n)
估计 n 范围内的素数数量
Definition prime_table.h:57
const ushort prime_short_table[6542]
void lmmp_prime_int_table_init_(uint n)
初始化全局素数表
Definition prime_table.c:99
ushort lmmp_prime_cnt16_(ushort n)
计算小于等于 n 的素数数量
void lmmp_prime_cache_init_(prime_cache_t *cache, uint n)
初始化素数表缓存
#define TEMP_DECL
Definition tmp_alloc.h:131
#define TEMP_FREE
Definition tmp_alloc.h:150
#define SALLOC_TYPE(n, type)
Definition tmp_alloc.h:144
#define TEMP_S_DECL
Definition tmp_alloc.h:133
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:148
#define TEMP_B_DECL
Definition tmp_alloc.h:132
#define BALLOC_TYPE(n, type)
Definition tmp_alloc.h:146
#define TEMP_S_FREE
Definition tmp_alloc.h:166
#define TEMP_B_FREE
Definition tmp_alloc.h:159