LAMMP 4.2.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
nPr.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/longlong.h"
20#include "../../../include/lammp/impl/mparam.h"
21#include "../../../include/lammp/impl/prime_table.h"
22
23
24#define mul_1(dst, rn, v) \
25 do { \
26 mp_limb_t _c_ = lmmp_mul_1_(dst, dst, rn, v); \
27 if (_c_ != 0) { \
28 ++rn; \
29 dst[rn - 1] = _c_; \
30 } \
31 } while (0)
32
33static const ulong odd_factorial[25] = {1, 1, 3, 3, 15, 45, 315, 315,
34 2835, 14175, 155925,
35 467775, 6081075, 42567525,
36 638512875, 638512875, 10854718875, 97692469875,
37 1856156927625, 9280784638125, 194896477400625,
38 2143861251406875, 49308808782358125,
39 147926426347074375ull, 3698160658676859375ull};
40
42 lmmp_param_assert(n >= r);
45 shl -= (n - r) - lmmp_limb_popcnt_(n - r);
46 *bits = shl;
47 if (n < ODD_FACTORIAL_SIZE || r <= 2) {
48 return 3;
49 } else if (n <= MP_UINT_MAX) {
50 uint64_t l1, l2;
52 if (n - r < ODD_FACTORIAL_SIZE)
53 l2 = 0;
54 else
55 l2 = log2_fac_floor(n - r);
56 mp_size_t rn = l1 - l2;
57 return (rn + LIMB_BITS - 1) / LIMB_BITS + 2; // more 2 limb
58 } else {
59 // nPr < (n - r/2 + 1)^r
60 ulong mean = n - r / 2 + 1;
61 return lmmp_pow_1_size_(mean, r);
62 }
63}
64
66 uint pn = n;
67 uint e = 0;
68 ulong inv = MP_ULONG_MAX / p + 1;
69 while (pn > 0) {
71 e += pn;
72 }
73 pn = r;
74 while (pn > 0) {
76 e -= pn;
77 }
78 if (e > 0) {
79 fac[nfactors].f = p;
80 fac[nfactors++].j = e;
81 }
82 return nfactors;
83}
84
85/**
86 * @brief 使用累乘函数计算nPr(奇数部分)
87 */
91 mp_size_t limbn = 0;
92 ulong t = 1;
93 uint v;
94 mp_bitcnt_t cnt = 0;
95 for (uint i = n - r + 1; i <= n; ++i) {
96 ctz_shr_u32(v, i, cnt);
97 t *= v;
98 if (t > MP_UINT_MAX) {
99 limbs[limbn++] = t;
100 t = 1;
101 }
102 }
103 if (t != 1)
104 limbs[limbn++] = t;
105
106 if (rn >= limbn) {
109 } else {
112 lmmp_copy(dst, tp, rn);
113 }
114 TEMP_FREE;
115 return rn;
116}
117
119 lmmp_param_assert(n >= r);
121 if (n < ODD_FACTORIAL_SIZE) {
122 if (n == 0) {
123 dst[0] = 1;
124 } else if (n == r) {
125 dst[0] = odd_factorial[n - 1];
126 } else {
127 dst[0] = odd_factorial[n - 1] / odd_factorial[n - r - 1];
128 }
129 return 1;
130 } else if (r <= 10) {
131 dst[0] = 1;
132 rn = 1;
133 ulong t = 1, v;
134 ulong i = n - r + 1;
135 mp_bitcnt_t cnt = 0;
136 lmmp_debug_assert(n >= 3);
137 for (; i <= n - 3; i += 3) {
138 t = i * (i + 1) * (i + 2);
139 ctz_shr_u64(v, t, cnt);
140 mul_1(dst, rn, v);
141 }
142 t = 1;
143 for (; i <= n; ++i) {
144 t *= i;
145 }
146 ctz_shr_u64(v, t, cnt);
147 if (v != 1) {
148 mul_1(dst, rn, v);
149 }
150 return rn;
151 } else if (n <= MP_UCHAR_MAX) {
152 lmmp_debug_assert(n >= 7);
153 lmmp_debug_assert(r >= 2);
154 dst[0] = 1;
155 rn = 1;
156 ulong t = 0, v;
157 ulong i = n - r + 1;
159 for (; i <= n - 7; i += 7) {
160 t = i * (i + 1) * (i + 2) * (i + 3) * (i + 4) * (i + 5) * (i + 6);
161 ctz_shr_u64(v, t, cnt);
162 mul_1(dst, rn, v);
163 }
164 t = 1;
165 for (; i <= n; ++i) {
166 t *= i;
167 }
168 ctz_shr_u64(v, t, cnt);
169 if (v != 1) {
170 mul_1(dst, rn, v);
171 }
172 return rn;
173 } else if (n <= 0xfff) {
175 ulongp restrict limbs = SALLOC_TYPE(r / 5 + 1, ulong);
176 mp_size_t limbn = 0;
177 ulong t, v;
178 ulong i = n - r + 1;
180 lmmp_debug_assert(n >= 5);
181 for (; i <= (ulong)n - 5; i += 5) {
182 t = i * (i + 1) * (i + 2) * (i + 3) * (i + 4);
183 ctz_shr_u64(v, t, cnt);
184 limbs[limbn++] = v;
185 }
186 t = 1;
187 for (; i <= n; ++i) {
188 t *= i;
189 }
190 ctz_shr_u64(v, t, cnt);
191 if (v != 1)
192 limbs[limbn++] = v;
194 // 这里不能直接乘入dst,因为dst的大小可能小于limbn,导致溢出
196 lmmp_copy(dst, tp, rn);
198 return rn;
200 /* 测量发现,累乘法和因子分解法的算法耗时流形交线大致为直线 */
201 return lmmp_odd_nPr_product_(dst, rn, n, r);
202 } else {
203 TEMP_DECL;
207 r = n - r;
208 nfactors = 0;
209 for (ushort i = 1; i < primen; ++i) {
212 }
213
215
216 TEMP_FREE;
217 return rn;
218 }
219}
220
222 lmmp_param_assert(n >= r);
224 if (r <= 10) {
225 dst[0] = 1;
226 rn = 1;
227 ulong v;
229 for (ulong i = n - r + 1; i <= n; ++i) {
230 ctz_shr_u64(v, i, cnt);
231 mul_1(dst, rn, v);
232 }
233 return rn;
235 /* 这个调优值是在近似忽略了质数表的初始化开销,主要瓶颈集中在质数表的遍历的情况下测得的 */
236 /* 因此,当质数表未初始化时,这个调优值将无法代表真实性能边界 */
237 return lmmp_odd_nPr_product_(dst, rn, n, r);
238 } else{
240
244 r = n - r;
245 nfactors = 0;
246
249 while (cache.is_end == 0) {
251 for (uint i = 0; i < cache.size; ++i) {
253 }
254 }
256
258
260 return rn;
261 }
262}
263
265 lmmp_param_assert(n >= r);
266 if (r < 10) {
267 dst[0] = 1;
268 rn = 1;
269 ulong v;
271 for (ulong i = n - r + 1; i <= n; ++i) {
272 ctz_shr_u64(v, i, cnt);
273 if (v != 1) {
274 mul_1(dst, rn, v);
275 }
276 }
277 return rn;
278 }
279 TEMP_DECL;
281 mp_size_t limbn = 0;
282 ulong v;
284 for (ulong t = n - r + 1; t <= n; ++t) {
285 ctz_shr_u64(v, t, cnt);
286 if (v != 1)
287 limbs[limbn++] = v;
288 }
289
290 if (rn >= limbn) {
293 } else {
296 lmmp_copy(dst, tp, rn);
297 }
298 TEMP_FREE;
299 return rn;
300}
301
303 lmmp_debug_assert(n >= r);
307
308 bits %= LIMB_BITS;
309 lmmp_zero(dst, shw);
310
311 if (n <= NPR_SHORT_LIMIT)
312 rn = lmmp_odd_nPr_ushort_(dst + shw, rn - shw, n, r);
313 else if (n <= NPR_INT_LIMIT)
314 rn = lmmp_odd_nPr_uint_(dst + shw, rn - shw, n, r);
315 else
316 rn = lmmp_odd_nPr_ulong_(dst + shw, rn - shw, n, r);
317
318 if (bits > 0) {
319 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
320 rn += shw + 1;
321 rn -= dst[rn - 1] == 0;
322 } else {
323 rn += shw;
324 }
325 return rn;
326}
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_ushort_(mp_ptr dst, mp_size_t rn, fac_ptr fac, ushort nfactors)
计算因子的累乘,并将结果放入dst中
mp_size_t lmmp_factors_mul_(mp_ptr dst, mp_size_t rn, fac_ptr fac, uint nfactors)
计算因子的累乘,并将结果放入dst中
#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 ctz_shr_u64(r, x, cnt)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition longlong.h:74
#define ctz_shr_u32(r, x, cnt)
Definition longlong.h:147
#define NPR_SHORT_LIMIT
Definition mparam.h:151
#define NPR_INT_LIMIT
Definition mparam.h:152
#define PERMUTATION_USHORT_B_THRESHOLD
Definition mparam.h:111
#define PERMUTATION_UINT_B_THRESHOLD
Definition mparam.h:113
#define MP_UINT_MAX
Definition mparam.h:136
#define MP_UCHAR_MAX
Definition mparam.h:134
#define PERMUTATION_UINT_K_THRESHOLD
Definition mparam.h:112
#define MP_ULONG_MAX
Definition mparam.h:137
#define PERMUTATION_USHORT_K_THRESHOLD
Definition mparam.h:110
#define ODD_FACTORIAL_SIZE
Definition mparam.h:149
#define t
#define tp
#define n
mp_size_t lmmp_nPr_size_(ulong n, ulong r, mp_bitcnt_t *restrict bits)
Definition nPr.c:41
#define mul_1(dst, rn, v)
Copyright (C) 2026 HJimmyK(Jericho Knox)
Definition nPr.c:24
static mp_size_t lmmp_odd_nPr_product_(mp_ptr restrict dst, mp_size_t rn, uint n, uint r)
使用累乘函数计算nPr(奇数部分)
Definition nPr.c:88
mp_size_t lmmp_odd_nPr_ulong_(mp_ptr restrict dst, mp_size_t rn, ulong n, ulong r)
Definition nPr.c:264
mp_size_t lmmp_odd_nPr_ushort_(mp_ptr restrict dst, mp_size_t rn, ulong n, ulong r)
Definition nPr.c:118
mp_size_t lmmp_odd_nPr_uint_(mp_ptr restrict dst, mp_size_t rn, ulong n, ulong r)
Definition nPr.c:221
static const ulong odd_factorial[25]
Definition nPr.c:33
static uint count_factors(fac_ptr fac, uint nfactors, uint n, uint r, uint p)
Definition nPr.c:65
mp_size_t lmmp_nPr_(mp_ptr restrict dst, mp_bitcnt_t bits, mp_size_t rn, ulong n, ulong r)
Definition nPr.c:302
mp_size_t lmmp_pow_1_size_(mp_limb_t base, ulong exp)
计算幂次方需要的limb缓冲区长度 base ^ exp
Definition pow.c:25
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