LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
factorial.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 if (n < 20) {
43 rn = 64;
44 } else {
46 }
47 rn = (rn + LIMB_BITS - 1) / LIMB_BITS + 2; // more two limbs
49 return rn;
50}
51
52/*
53 N N/2 N
54 +--+ / +--+ \ 2 / +--+ \
55 | | P_i ^ (e_i) = | | | P_i ^ (e_i / 2) | * | | | P_i ^ ( e_i mod 2) |
56 | | \ | | / \ | | /
57 i=0 i=0 i=0
58*/
59
62 lmmp_param_assert(rn > 0 && nfactors > 0);
64 // 绝大多数情况下,大的质因数的指数都很小,所以这里只需要考虑小的质因数。
65 dst[0] = 1;
66 rn = 1;
67 mp_limb_t t = 1;
68 for (uint i = 0; i < nfactors; i++) {
69 uint f = fac[i].f;
70 uint j = fac[i].j;
71 lmmp_debug_assert(j != 0 && f <= MP_USHORT_MAX);
72#define MAX_T 0xffffffffffff
73 for (uint e = 0; e < j; e++) {
74 t *= f;
75 if (t > MAX_T) {
76 mul_1(dst, rn, t);
77 t = 1;
78 }
79 }
80 }
81 if (t != 1) {
82 mul_1(dst, rn, t);
83 }
84#undef MAX_T
85 return rn;
86 } else {
90 ulong t = 1;
91 mp_size_t limbn = 0;
92 for (uint i = 0; i < nfactors; ++i) {
93 uint f = fac[i].f;
94 uint j = fac[i].j;
95 if (j > 1) {
96 fac[new_nfactors].f = f;
97 fac[new_nfactors++].j = j >> 1;
98 }
99 if (j & 1) {
100 t *= f;
101 if (t > MP_UINT_MAX) {
102 limbs[limbn++] = t;
103 t = 1;
104 }
105 }
106 }
107 if (t != 1) {
108 limbs[limbn++] = t;
109 }
110
112 mp_size_t mpn = 0;
113
114 if (new_nfactors > 0) {
115 if (limbn > 0) {
118 mp_size_t tn = ((rn - mpn) >> 1) + 1;
119 // 这里根据mpn的大小估计剩余因子乘积的长度,额外分配两倍的tn,以进行平方。
120 mp_ptr restrict tp = BALLOC_TYPE(3 * tn + 3, mp_limb_t);
122
123 mp_ptr restrict tp2 = tp + tn + 1;
124 lmmp_sqr_(tp2, tp, tn);
125 tn <<= 1;
126 tn -= tp2[tn - 1] == 0;
127 MUL(dst, tp2, tn, mp, mpn);
128 rn = tn + mpn;
129 rn -= dst[rn - 1] == 0;
130 } else {
131 mp_size_t tn = (rn >> 1) + 1;
134 lmmp_sqr_(dst, tp, tn);
135 rn = tn << 1;
136 rn -= dst[rn - 1] == 0;
137 }
138 } else {
140 // 这里不能直接乘入dst,因为dst的大小可能小于limbn,导致溢出
141 if (rn >= limbn) {
143 } else {
145 lmmp_copy(dst, mp, rn);
146 }
147 }
148 TEMP_FREE;
149 return rn;
150 }
151}
152
153static inline void count_factors(fac_ptr fac, uint nfactors, uint n, uint p) {
154 uint pn = n;
155 uint e = 0;
156 while (pn > 0) {
157 pn /= p;
158 e += pn;
159 }
160 fac[nfactors].f = p;
161 fac[nfactors].j = e;
162}
163
168
173 nfactors = 0;
174
177 while (cache.is_end == 0) {
179 for (uint i = 0; i < cache.size; i++) {
180 // 对于阶乘n!,对于所有小于等于n的质数,贡献都至少为1
181 count_factors(fac, nfactors++, n, cache.pp[i]);
182 }
183 }
185
187
189 return rn;
190}
191
196 bits %= LIMB_BITS;
197 lmmp_zero(dst, shw);
198
199 if (n <= NPR_SHORT_LIMIT)
201 else
203
204 if (bits > 0) {
205 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
206 rn += shw + 1;
207 rn -= dst[rn - 1] == 0;
208 } else {
209 rn += shw;
210 }
211 return rn;
212}
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_factorial_(mp_ptr restrict dst, mp_bitcnt_t bits, mp_size_t rn, uint n)
Definition factorial.c:192
#define MUL(dst, ap, an, bp, bn)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition factorial.c:26
#define MAX_T
#define mul_1(dst, rn, v)
Definition factorial.c:33
mp_size_t lmmp_odd_factorial_uint_(mp_ptr restrict dst, mp_size_t rn, uint n)
Definition factorial.c:164
static void count_factors(fac_ptr fac, uint nfactors, uint n, uint p)
Definition factorial.c:153
mp_size_t lmmp_factorial_size_(uint n, mp_bitcnt_t *restrict bits)
Definition factorial.c:40
mp_size_t lmmp_factors_mul_(mp_ptr restrict dst, mp_size_t rn, fac_ptr restrict fac, uint nfactors)
Definition factorial.c:60
#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
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 NPR_SHORT_LIMIT
Definition mparam.h:151
#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 t
#define tp
#define 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
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
void lmmp_prime_int_table_init_(uint n)
初始化全局素数表
Definition prime_table.c:99
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 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_B_FREE
Definition tmp_alloc.h:159