LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
arith_seqprod.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/ele_mul.h"
8#include "../../../include/lammp/impl/mparam.h"
9#include "../../../include/lammp/impl/tmp_alloc.h"
10#include "../../../include/lammp/impl/longlong.h"
11#include "../../../include/lammp/lmmpn.h"
12#include "../../../include/lammp/numth.h"
13
15 double x_m = (double)x / m;
16 double log_l = (n + 1) * log(m) + lgamma(x_m + n + 1) - lgamma(x_m);
17 double log2_l = log_l / LOG2_;
18 mp_size_t rn = ceil(log2_l / LIMB_BITS) + 2; /* more two limbs */
19 return rn;
20}
21
22static inline mp_size_t _odd_pow_(mp_ptr dst, mp_size_t rn, uint base, ulong exp) {
23 if (base <= 0xf)
24 return lmmp_u4_pow_1_(dst, rn, base, exp);
25 else if (base <= MP_UCHAR_MAX)
26 return lmmp_u8_pow_1_(dst, rn, base, exp);
27 else if (base <= MP_USHORT_MAX)
28 return lmmp_u16_pow_1_(dst, rn, base, exp);
29 else
30 return lmmp_u32_pow_1_(dst, rn, base, exp);
31}
32
33static inline mp_size_t _odd_nPr_(mp_ptr restrict dst, mp_size_t rn, ulong n, ulong r) {
34 if (n <= NPR_SHORT_LIMIT) {
35 return lmmp_odd_nPr_ushort_(dst, rn, n, r);
36 } else {
37 return lmmp_odd_nPr_uint_(dst, rn, n, r);
38 }
39}
40
41/*
42当x=p*m时,
43x(x+m)...(x+n*m) = p*m * (p+1)*m * ... * (p+n)*m
44 = m^(n+1) * p(p+1)...(p+n)
45分别计算幂和组合数,然后相乘
46*/
47static inline mp_size_t pow_nPr_(mp_ptr restrict dst, mp_size_t rn, uint x, uint n, uint m) {
49 uint p = x / m;
50
51 mp_bitcnt_t bits;
52 mp_size_t tn = lmmp_nPr_size_(p + n, n + 1, &bits);
53 tn -= bits / LIMB_BITS;
54 mp_ptr restrict tp = TALLOC_TYPE(tn, mp_limb_t);
55 tn = _odd_nPr_(tp, tn, p + n, n + 1);
56
58 m >>= tz;
59 mp_size_t mpown = lmmp_pow_1_size_(m, n + 1);
60 mp_ptr restrict mpow = TALLOC_TYPE(mpown, mp_limb_t);
61 mpown = _odd_pow_(mpow, mpown, m, n + 1);
62
63 bits += tz * (n + 1);
64 mp_size_t shw = bits / LIMB_BITS;
65 bits %= LIMB_BITS;
66
67 lmmp_zero(dst, shw);
68 if (tn >= mpown)
69 lmmp_mul_(dst + shw, tp, tn, mpow, mpown);
70 else
71 lmmp_mul_(dst + shw, mpow, mpown, tp, tn);
72
73 rn = tn + mpown;
74 rn -= dst[shw + rn - 1] == 0 ? 1 : 0;
75 if (bits > 0) {
76 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
77 rn += shw + 1;
78 rn -= dst[rn - 1] == 0 ? 1 : 0;
79 } else {
80 rn += shw;
81 }
83 return rn;
84}
85
87 lmmp_param_assert(dst != NULL);
88 lmmp_param_assert(rn >= 1);
89 lmmp_param_assert(x >= 1);
90 lmmp_param_assert(n >= 1);
91 lmmp_param_assert(m > 1);
92
93 if (x % m == 0) {
94 return pow_nPr_(dst, rn, x, n, m);
95 }
96
97 mp_bitcnt_t bits = 0;
98 while ((x & 1) == 0 && (m & 1) == 0) {
99 x >>= 1;
100 m >>= 1;
101 bits++;
102 }
103 bits *= n + 1;
104
105 TEMP_DECL;
106 ulongp restrict limbs = TALLOC_TYPE((n + 1) / 2 + 1, ulong);
107 mp_size_t limbn = 0;
108 ulong t = 1, s, v;
109 mp_bitcnt_t cnt;
110 for (uint i = 0; i <= n; i++) {
111 s = x + i * m;
112 ctz_shl(v, s, cnt);
113 t *= v;
114 bits += cnt;
115 if (t > MP_UINT_MAX) {
116 limbs[limbn++] = t;
117 t = 1;
118 }
119 }
120 ctz_shl(v, t, cnt);
121 bits += cnt;
122 if (v != 1) {
123 limbs[limbn++] = v;
124 }
125 mp_size_t shw = bits / LIMB_BITS;
126 bits %= LIMB_BITS;
127 mp_ptr restrict b = TALLOC_TYPE(limbn * 2, mp_limb_t);
128 mp_size_t bn = lmmp_elem_mul_ulong_(b, limbs, limbn, b + limbn);
129 lmmp_zero(dst, shw);
130 if (bits > 0) {
131 dst[shw + bn] = lmmp_shl_(dst + shw, b, bn, bits);
132 rn = bn + shw + 1;
133 rn -= dst[rn - 1] == 0 ? 1 : 0;
134 } else {
135 lmmp_copy(dst + shw, b, bn);
136 rn = bn + shw;
137 }
138 TEMP_FREE;
139 return rn;
140}
mp_size_t lmmp_arith_seqprod_size_(uint x, uint n, uint m)
计算等差数列乘积 x(x+m)...(x+n*m)的 limb 缓冲区长度
static mp_size_t pow_nPr_(mp_ptr restrict dst, mp_size_t rn, uint x, uint n, uint m)
static mp_size_t _odd_pow_(mp_ptr dst, mp_size_t rn, uint base, ulong exp)
static mp_size_t _odd_nPr_(mp_ptr restrict dst, mp_size_t rn, ulong n, ulong r)
mp_size_t lmmp_arith_seqprod_(mp_ptr restrict dst, mp_size_t rn, uint x, uint n, uint m)
mp_size_t lmmp_elem_mul_ulong_(mp_ptr dst, const ulongp limbs, mp_size_t n, mp_ptr tp)
计算limbs数组的累乘积
#define bn
mp_limb_t * mp_ptr
Definition lmmp.h:215
#define lmmp_copy(dst, src, n)
Definition lmmp.h:364
#define lmmp_zero(dst, n)
Definition lmmp.h:366
size_t mp_bitcnt_t
Definition lmmp.h:217
uint64_t mp_size_t
Definition lmmp.h:212
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
int lmmp_tailing_zeros_(mp_limb_t x)
计算一个单精度数(limb)中末尾零的个数
Definition tiny.c:54
void lmmp_mul_(mp_ptr dst, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
不等长大数乘法操作 [dst,na+nb] = [numa,na] * [numb,nb]
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:9
#define ctz_shl(r, x, cnt)
Definition longlong.h:229
#define NPR_SHORT_LIMIT
Definition mparam.h:154
#define MP_UINT_MAX
Definition mparam.h:139
#define MP_UCHAR_MAX
Definition mparam.h:137
#define MP_USHORT_MAX
Definition mparam.h:138
#define LOG2_
Definition mparam.h:165
#define tp
mp_size_t lmmp_u4_pow_1_(mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
计算幂次方 [dst,rn] = [base,1] ^ exp
mp_size_t lmmp_odd_nPr_ushort_(mp_ptr dst, mp_size_t rn, ulong n, ulong r)
计算 nPr 排列数的奇数部分
mp_size_t lmmp_u32_pow_1_(mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
计算幂次方 [dst,rn] = [base,1] ^ exp
uint64_t * ulongp
Definition numth.h:45
uint32_t uint
Definition numth.h:35
static mp_size_t lmmp_pow_1_size_(mp_limb_t base, ulong exp)
计算幂次方需要的limb缓冲区长度 base ^ exp
Definition numth.h:264
mp_size_t lmmp_u8_pow_1_(mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
计算幂次方 [dst,rn] = [base,1] ^ exp
mp_size_t lmmp_u16_pow_1_(mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
计算幂次方 [dst,rn] = [base,1] ^ exp
mp_size_t lmmp_nPr_size_(ulong n, ulong r, mp_bitcnt_t *bits)
计算 nPr 排列数的 limb 缓冲区长度
uint64_t ulong
Definition numth.h:36
mp_size_t lmmp_odd_nPr_uint_(mp_ptr dst, mp_size_t rn, ulong n, ulong r)
计算 nPr 排列数的奇数部分
#define TEMP_DECL
Definition tmp_alloc.h:72
#define TEMP_FREE
Definition tmp_alloc.h:93
#define TALLOC_TYPE(n, type)
Definition tmp_alloc.h:91