LAMMP 4.1.0
Lamina High-Precision Arithmetic Library
载入中...
搜索中...
未找到
numth.h 文件参考
#include <math.h>
#include <stdbool.h>
#include "lmmp.h"
+ numth.h 的引用(Include)关系图:
+ 此图展示该文件直接或间接的被哪些文件引用了:

浏览源代码.

宏定义

#define INLINE_   static inline
 

类型定义

typedef int8_t schar
 
typedef int8_t * scharp
 
typedef int32_t sint
 
typedef int32_t * sintp
 
typedef int64_t slong
 
typedef int64_t * slongp
 
typedef int16_t sshort
 
typedef int16_t * sshortp
 
typedef uint8_t uchar
 
typedef uint8_t * ucharp
 
typedef uint32_t uint
 
typedef uint32_t * uintp
 
typedef uint64_t ulong
 
typedef uint64_t * ulongp
 
typedef uint16_t ushort
 
typedef uint16_t * ushortp
 

函数

mp_size_t lmmp_arith_seqprod_ (mp_ptr dst, mp_size_t rn, uint x, uint n, uint m)
 计算等差数列乘积 x(x+m)...(x+n*m)
 
mp_size_t lmmp_arith_seqprod_size_ (uint x, uint n, uint m)
 计算等差数列乘积 x(x+m)...(x+n*m)的 limb 缓冲区长度
 
void lmmp_binvert_2_ (mp_ptr dst, mp_srcptr numa)
 计算 [numa,2] 在B^2下的逆元
 
void lmmp_binvert_3_ (mp_ptr dst, mp_srcptr numa)
 计算 [numa,3] 在B^3下的逆元
 
void lmmp_binvert_4_ (mp_ptr dst, mp_srcptr numa)
 计算 [numa,4] 在B^4下的逆元
 
void lmmp_binvert_n_dc_ (mp_ptr dst, mp_srcptr numa, mp_size_t n, mp_ptr tp)
 计算 [numa,n] 在B^n下的逆元
 
uint lmmp_binvert_uint_ (uint a)
 计算 a 在2^32下的逆元
 
ulong lmmp_binvert_ulong_ (ulong a)
 计算 a 在2^64下的逆元
 
mp_size_t lmmp_factorial_ (mp_ptr dst, mp_bitcnt_t bits, mp_size_t rn, uint n)
 计算 n! 阶乘
 
mp_size_t lmmp_factorial_size_ (uint n, mp_bitcnt_t *bits)
 计算 n! 阶乘的 limb 缓冲区长度
 
mp_limb_t lmmp_gcd_11_ (mp_limb_t u, mp_limb_t v)
 计算 [numa,na] 在B^n 下的逆元
 
mp_limb_t lmmp_gcd_1_ (mp_srcptr up, mp_size_t un, mp_limb_t vlimb)
 计算两个无符号整数的最大公约数
 
mp_size_t lmmp_gcd_22_ (mp_ptr dst, mp_srcptr up, mp_srcptr vp)
 计算两个无符号整数的最大公约数
 
mp_size_t lmmp_gcd_2_ (mp_ptr dst, mp_srcptr up, mp_size_t un, mp_srcptr vp)
 计算两个无符号整数的最大公约数
 
mp_size_t lmmp_gcd_basecase_ (mp_ptr dst, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
 计算两个无符号整数的最大公约数(不建议使用此算法,更高版本可能被彻底弃用)
 
mp_size_t lmmp_gcd_lehmer_ (mp_ptr dst, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
 计算两个无符号整数的最大公约数(Lehmer算法)
 
bool lmmp_is_prime_uint_ (uint n)
 判断素数
 
bool lmmp_is_prime_ulong_ (ulong n)
 判断素数
 
ulong lmmp_mulmod_ulong_ (ulong a, ulong b, ulong mod, ulongp q)
 计算两个无符号整数的乘积,对mod取模,商放入 q 中
 
mp_size_t lmmp_multinomial_ (mp_ptr dst, mp_size_t rn, uint n, const uintp r, uint m)
 计算多项式系数
 
mp_size_t lmmp_multinomial_size_ (const uintp r, uint m, ulong *n)
 计算多项式系数的 limb 缓冲区长度
 
mp_size_t lmmp_nCr_ (mp_ptr dst, mp_bitcnt_t bits, mp_size_t rn, uint n, uint r)
 计算 nCr 组合数 ( nCr = n! / (r!(n-r)!) )
 
mp_size_t lmmp_nCr_size_ (uint n, uint r, mp_bitcnt_t *bits)
 计算 nCr 组合数的 limb 缓冲区长度
 
ulong lmmp_next_prime_ulong_ (ulong n)
 大于n的下一个素数
 
mp_size_t lmmp_nPr_ (mp_ptr dst, mp_bitcnt_t bits, mp_size_t rn, ulong n, ulong r)
 计算 nPr 排列数 ( nPr = n! / (n-r)! )
 
mp_size_t lmmp_nPr_size_ (ulong n, ulong r, mp_bitcnt_t *bits)
 计算 nPr 排列数的 limb 缓冲区长度
 
mp_size_t lmmp_odd_factorial_uint_ (mp_ptr dst, mp_size_t rn, uint n)
 计算 n! 阶乘的奇数部分
 
mp_size_t lmmp_odd_nCr_uint_ (mp_ptr dst, mp_size_t rn, uint n, uint r)
 计算 nCr 组合数的奇数部分
 
mp_size_t lmmp_odd_nCr_ushort_ (mp_ptr dst, mp_size_t rn, uint n, uint r)
 计算 nCr 组合数的奇数部分
 
mp_size_t lmmp_odd_nPr_uint_ (mp_ptr dst, mp_size_t rn, ulong n, ulong r)
 计算 nPr 排列数的奇数部分
 
mp_size_t lmmp_odd_nPr_ulong_ (mp_ptr dst, mp_size_t rn, ulong n, ulong r)
 计算 nPr 排列数的奇数部分
 
mp_size_t lmmp_odd_nPr_ushort_ (mp_ptr dst, mp_size_t rn, ulong n, ulong r)
 计算 nPr 排列数的奇数部分
 
mp_size_t lmmp_pow_ (mp_ptr dst, mp_size_t rn, mp_srcptr base, mp_size_t n, ulong exp)
 计算大整数幂 [dst,rn] = [base,n] ^ exp
 
mp_size_t lmmp_pow_1_ (mp_ptr dst, mp_size_t rn, mp_limb_t base, ulong exp)
 计算幂次方 [dst,rn] = [base,1] ^ exp
 
static mp_size_t lmmp_pow_1_size_ (mp_limb_t base, ulong exp)
 计算幂次方需要的limb缓冲区长度 base ^ exp
 
mp_size_t lmmp_pow_basecase_ (mp_ptr dst, mp_size_t rn, mp_srcptr base, mp_size_t n, ulong exp)
 计算奇数次幂算法 [dst,rn] = [base,n] ^ exp
 
static mp_size_t lmmp_pow_size_ (mp_srcptr base, mp_size_t n, ulong exp)
 计算幂次方需要的limb缓冲区长度 [base,n] ^ exp
 
mp_size_t lmmp_pow_win2_ (mp_ptr dst, mp_size_t rn, mp_srcptr base, mp_size_t n, ulong exp)
 计算幂次方2比特窗口快速幂算法 [dst,rn] = [base,n] ^ exp
 
uint lmmp_powmod_uint_ (uint base, ulong exp, uint mod)
 计算 base^exp 对 mod 取模
 
ulong lmmp_powmod_ulong_ (ulong base, ulong exp, ulong mod)
 计算 base^exp 对 mod 取模
 
ulong lmmp_prev_prime_ulong_ (ulong n)
 小于等于n的上一个素数
 
mp_size_t lmmp_remove_ (mp_ptr np, mp_size_t *nn, mp_srcptr dp, mp_size_t dn)
 除去[np,nn]中的[dp,dn]的因子
 
ushortp lmmp_trialdiv_ (mp_srcptr np, mp_size_t nn, ushort N, ushort *rn)
 试除法
 
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_u32_pow_1_ (mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
 计算幂次方 [dst,rn] = [base,1] ^ exp
 
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_u64_pow_1_ (mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
 计算幂次方 [dst,rn] = [base,1] ^ exp
 
mp_size_t lmmp_u8_pow_1_ (mp_ptr dst, mp_size_t rn, ulong base, ulong exp)
 计算幂次方 [dst,rn] = [base,1] ^ exp
 

宏定义说明

◆ INLINE_

#define INLINE_   static inline

在文件 numth.h49 行定义.

类型定义说明

◆ schar

typedef int8_t schar

在文件 numth.h32 行定义.

◆ scharp

typedef int8_t* scharp

在文件 numth.h40 行定义.

◆ sint

typedef int32_t sint

在文件 numth.h37 行定义.

◆ sintp

typedef int32_t* sintp

在文件 numth.h44 行定义.

◆ slong

typedef int64_t slong

在文件 numth.h38 行定义.

◆ slongp

typedef int64_t* slongp

在文件 numth.h46 行定义.

◆ sshort

typedef int16_t sshort

在文件 numth.h34 行定义.

◆ sshortp

typedef int16_t* sshortp

在文件 numth.h42 行定义.

◆ uchar

typedef uint8_t uchar

在文件 numth.h31 行定义.

◆ ucharp

typedef uint8_t* ucharp

在文件 numth.h39 行定义.

◆ uint

typedef uint32_t uint

在文件 numth.h35 行定义.

◆ uintp

typedef uint32_t* uintp

在文件 numth.h43 行定义.

◆ ulong

typedef uint64_t ulong

在文件 numth.h36 行定义.

◆ ulongp

typedef uint64_t* ulongp

在文件 numth.h45 行定义.

◆ ushort

typedef uint16_t ushort

在文件 numth.h33 行定义.

◆ ushortp

typedef uint16_t* ushortp

在文件 numth.h41 行定义.

函数说明

◆ lmmp_arith_seqprod_()

mp_size_t lmmp_arith_seqprod_ ( mp_ptr  dst,
mp_size_t  rn,
uint  x,
uint  n,
uint  m 
)

计算等差数列乘积 x(x+m)...(x+n*m)

参数
dst结果指针
rn结果指针的 limb 长度
x首项
n等差数列共n+1项
m公差(大于1)
警告
x>0, m>1, n>0, dst!=NULL, rn>0, x+n*m<=0xffffffff
返回
结果的实际的 limb 缓冲区长度

◆ lmmp_arith_seqprod_size_()

mp_size_t lmmp_arith_seqprod_size_ ( uint  x,
uint  n,
uint  m 
)

计算等差数列乘积 x(x+m)...(x+n*m)的 limb 缓冲区长度

参数
x首项
n等差数列共n+1项
m公差
警告
x>0, m>1, n>0
返回
等差数列乘积的 limb 缓冲区长度(比实际长度多 1-2 个 limb)

在文件 arith_seqprod.c14 行定义.

14 {
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}
uint64_t mp_size_t
Definition lmmp.h:212
#define LIMB_BITS
Definition lmmp.h:221
#define LOG2_
Definition mparam.h:165

引用了 LIMB_BITS , 以及 LOG2_.

◆ lmmp_binvert_2_()

void lmmp_binvert_2_ ( mp_ptr  dst,
mp_srcptr  numa 
)

计算 [numa,2] 在B^2下的逆元

参数
numa待求逆元指针(长度为 2 个limb)
dst结果指针(长度为 2 个limb)
警告
numa!=NULL, dst!=NULL, numa[0]%2==1, eqsep(dst,numa)

在文件 binvert_1.c47 行定义.

47 {
48 lmmp_param_assert(numa[0] % 2 == 1);
49 mp_limb_t k, t;
50 mp_limb_t a1 = numa[1];
51 mp_limb_t a0 = numa[0];
53 mp_limb_t z;
54 /*
55 xn * a0 == 1 + k * B
56 yn := xn * (2 - a * xn) mod B^2
57 := xn * (2 - a0 * xn - a1 * xn * B) mod B^2
58 := xn * (2 - 1 - k*B - a1 * xn * B) mod B^2
59 := xn * (1 - k*B - a1 * xn * B) mod B^2
60 := (xn - xn*k * B - a1 * xn^2 * B) mod B^2
61 */
62 _umul64to128_(a0, xn, &t, &k);
63 z = xn * k;
64 z += a1 * xn * xn;
65 dst[0] = xn;
66 dst[1] = -z;
67}
#define k
ulong lmmp_binvert_ulong_(ulong a)
计算 a 在2^64下的逆元
Definition binvert_1.c:33
#define xn
uint64_t mp_limb_t
Definition lmmp.h:211
#define lmmp_param_assert(x)
Definition lmmp.h:398
static void _umul64to128_(uint64_t a, uint64_t b, uint64_t *low, uint64_t *high)
Definition longlong.h:31
#define a0
#define a1

引用了 _umul64to128_(), a0, a1, k, lmmp_binvert_ulong_(), lmmp_param_assert , 以及 xn.

被这些函数引用 lmmp_binvert_3_(), lmmp_binvert_4_() , 以及 lmmp_binvert_n_dc_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_binvert_3_()

void lmmp_binvert_3_ ( mp_ptr  dst,
mp_srcptr  numa 
)

计算 [numa,3] 在B^3下的逆元

参数
numa待求逆元指针(长度为 3 个limb)
dst结果指针(长度为 3 个limb)
警告
numa!=NULL, dst!=NULL, numa[0]%2==1, sep(dst,numa)

被这些函数引用 lmmp_binvert_n_dc_().

+ 这是这个函数的调用关系图:

◆ lmmp_binvert_4_()

void lmmp_binvert_4_ ( mp_ptr  dst,
mp_srcptr  numa 
)

计算 [numa,4] 在B^4下的逆元

参数
numa待求逆元指针(长度为 4 个limb)
dst结果指针(长度为 4 个limb)
警告
numa!=NULL, dst!=NULL, numa[0]%2==1, sep(dst,numa)

被这些函数引用 lmmp_binvert_n_dc_().

+ 这是这个函数的调用关系图:

◆ lmmp_binvert_n_dc_()

void lmmp_binvert_n_dc_ ( mp_ptr  dst,
mp_srcptr  numa,
mp_size_t  n,
mp_ptr  tp 
)

计算 [numa,n] 在B^n下的逆元

参数
numa待求逆元指针(长度为 n 个limb)
dst结果指针(长度为 n 个limb)
n结果的 limb 长度
tp临时工作区指针(长度为 5*(n+1)/2 个limb)
警告
numa!=NULL, dst!=NULL, numa[0]%2==1, sep(dst,numa,tp)

◆ lmmp_binvert_uint_()

uint lmmp_binvert_uint_ ( uint  a)

计算 a 在2^32下的逆元

参数
a待求逆元
警告
a%2==1
返回
逆元

在文件 binvert_1.c21 行定义.

21 {
22 lmmp_param_assert(a % 2 == 1);
23 ulong r, y;
24
25 r = binv_tab[(a / 2) & 0x7F]; /* 8 bits */
26 y = 1 - a * r;
27 r = r * (1 + y); /* 16 bits */
28 y *= y;
29 r = r * (1 + y); /* 32 bits */
30 return r;
31}
static const unsigned char binv_tab[128]
Definition binvert_1.c:13
uint64_t ulong
Definition numth.h:36

引用了 binv_tab , 以及 lmmp_param_assert.

◆ lmmp_binvert_ulong_()

ulong lmmp_binvert_ulong_ ( ulong  a)

计算 a 在2^64下的逆元

参数
a待求逆元
警告
a%2==1
返回
逆元

在文件 binvert_1.c33 行定义.

33 {
34 lmmp_param_assert(a % 2 == 1);
35 ulong r, y;
36
37 r = binv_tab[(a / 2) & 0x7F]; /* 8 bits */
38 y = 1 - a * r;
39 r = r * (1 + y); /* 16 bits */
40 y *= y;
41 r = r * (1 + y); /* 32 bits */
42 y *= y;
43 r = r * (1 + y); /* 64 bits */
44 return r;
45}

引用了 binv_tab , 以及 lmmp_param_assert.

被这些函数引用 lmmp_binvert_2_(), lmmp_binvert_n_dc_(), lmmp_is_prime_notrial_() , 以及 lmmp_powmod_ulong_().

+ 这是这个函数的调用关系图:

◆ lmmp_factorial_()

mp_size_t lmmp_factorial_ ( mp_ptr  dst,
mp_bitcnt_t  bits,
mp_size_t  rn,
uint  n 
)

计算 n! 阶乘

参数
dst结果指针
bitsn! 的2的因子数
rn结果指针的 limb 长度
n阶乘的阶数
警告
dst!=NULL, rn>0
返回
返回 dst 的实际 limb 长度

◆ lmmp_factorial_size_()

mp_size_t lmmp_factorial_size_ ( uint  n,
mp_bitcnt_t bits 
)

计算 n! 阶乘的 limb 缓冲区长度

参数
n阶乘的阶数
bits被修改为 n! 的2的因子数
返回
n! 阶乘的 limb 缓冲区长度(比实际长度多 1-2 个 limb)

◆ lmmp_gcd_11_()

mp_limb_t lmmp_gcd_11_ ( mp_limb_t  u,
mp_limb_t  v 
)

计算 [numa,na] 在B^n 下的逆元

参数
dst结果指针(长度为 n 个limb)
numa待求逆元指针(长度为 na 个limb)
na待求逆元的 limb 长度
n结果的 limb 长度
警告
n>=na>0, numa!=NULL, dst!=NULL, numa[0]%2==1, sep(dst,numa)
返回
dst 的实际 limb 长度

计算两个无符号整数的最大公约数

参数
u第一个无符号整数
v第二个无符号整数
返回
最大公约数
警告
u!=0, v!=0

在文件 gcd_1.c10 行定义.

10 {
11 lmmp_param_assert(u > 0 && v > 0);
12 int count, k;
13 k = lmmp_tailing_zeros_(u | v);
14 u >>= lmmp_tailing_zeros_(u);
15 v >>= lmmp_tailing_zeros_(v);
16 while (u != v) {
17 if (u > v) {
18 u -= v;
19 count = lmmp_tailing_zeros_(u);
20 u >>= count;
21 } else {
22 v -= u;
23 count = lmmp_tailing_zeros_(v);
24 v >>= count;
25 }
26 }
27 return u << k;
28}
#define k
int lmmp_tailing_zeros_(mp_limb_t x)
计算一个单精度数(limb)中末尾零的个数
Definition tiny.c:54

引用了 k, lmmp_param_assert , 以及 lmmp_tailing_zeros_().

被这些函数引用 lmmp_gcd_1_(), lmmp_gcd_22_() , 以及 lmmp_gcd_lehmer_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_gcd_1_()

mp_limb_t lmmp_gcd_1_ ( mp_srcptr  up,
mp_size_t  un,
mp_limb_t  vlimb 
)

计算两个无符号整数的最大公约数

参数
up第一个无符号整数指针
un第一个无符号整数的 limb 长度
v第二个无符号整数
警告
v!=0, up!=NULL, un>0
返回
最大公约数

在文件 gcd_1.c30 行定义.

30 {
31 lmmp_param_assert(un > 0);
32 lmmp_param_assert(vlimb > 0);
33 mp_limb_t ulimb;
34 if (un == 1) {
35 ulimb = up[0];
36 }
37 else {
38 ulimb = lmmp_mod_1_(up, un, vlimb);
39 }
40 if (ulimb == 0)
41 return vlimb;
42 else
43 return lmmp_gcd_11_(ulimb, vlimb);
44}
mp_limb_t lmmp_gcd_11_(mp_limb_t u, mp_limb_t v)
计算 [numa,na] 在B^n 下的逆元
Definition gcd_1.c:10
mp_limb_t lmmp_mod_1_(mp_srcptr numa, mp_size_t na, mp_limb_t x)
单精度数取余
Definition div.c:20

引用了 lmmp_gcd_11_(), lmmp_mod_1_() , 以及 lmmp_param_assert.

被这些函数引用 lmmp_gcd_lehmer_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_gcd_22_()

mp_size_t lmmp_gcd_22_ ( mp_ptr  dst,
mp_srcptr  up,
mp_srcptr  vp 
)

计算两个无符号整数的最大公约数

参数
up第一个无符号整数指针,长度为 2
vp第二个无符号整数指针,长度为 2
dst结果指针(长度为 2,两个 limb 都会进行写入,即使最高位可能为0)
警告
up!=NULL, vp!=NULL, [up,2]!=0, [vp,2]!=0, dst!=NULL, eqsep(dst,[up|vp])
注解
我们不要求 up 和 vp 的高位不为 0,但要求两个数均不可以高低位全为 0
返回
dst 的实际 limb 长度

在文件 gcd_2.c11 行定义.

11 {
12 lmmp_param_assert(dst != NULL);
13 lmmp_param_assert(up != NULL);
14 lmmp_param_assert(vp != NULL);
15 lmmp_param_assert(!(up[1] == 0 && up[0] == 0));
16 lmmp_param_assert(!(vp[1] == 0 && vp[0] == 0));
17 mp_limb_t u[2] = { up[0], up[1] };
18 mp_limb_t v[2] = { vp[0], vp[1] };
19 int k, cnt;
20
21 if (u[1] == 0 && v[1] == 0) {
22 dst[0] = lmmp_gcd_11_(u[0], v[0]);
23 dst[1] = 0;
24 return 1;
25 } else if (u[1] == 0) {
26 cnt = lmmp_tailing_zeros_(u[0] | v[0]);
27 u[0] = u[0] >> lmmp_tailing_zeros_(u[0]);
28 goto gcd_1_2;
29 } else if (v[1] == 0) {
30 cnt = lmmp_tailing_zeros_(u[0] | v[0]);
31 v[0] = v[0] >> lmmp_tailing_zeros_(v[0]);
32 goto gcd_2_1;
33 }
34
35 if (u[0] == 0 && v[0] == 0) {
36 dst[0] = lmmp_gcd_11_(u[1], v[1]);
37 dst[1] = 0;
38 return 1;
39 } else if (u[0] == 0) {
40 u[0] = u[1] >> lmmp_tailing_zeros_(u[1]);
41 cnt = lmmp_tailing_zeros_(v[0]);
42 goto gcd_1_2;
43 } else if (v[0] == 0) {
44 v[0] = v[1] >> lmmp_tailing_zeros_(v[1]);
45 cnt = lmmp_tailing_zeros_(u[0]);
46 goto gcd_2_1;
47 }
48 cnt = lmmp_tailing_zeros_(u[0] | v[0]);
49 k = lmmp_tailing_zeros_(u[0]);
50
51 if (k > 0)
52 _u128lshr(u, u, k);
53 k = lmmp_tailing_zeros_(v[0]);
54 if (k > 0)
55 _u128lshr(v, v, k);
56 while (!(u[0] == v[0] && u[1] == v[1])) {
57 if (u[1] == 0 && v[1] != 0) goto gcd_1_2;
58 if (v[1] == 0 && u[1] != 0) goto gcd_2_1;
59 if (u[1] == 0 && v[1] == 0) goto gcd_1_1;
60
61 if (_u128cmp(u, v)) {
62 _u128sub(v, v, u);
63 if (v[0] == 0) {
64 v[0] = v[1] >> lmmp_tailing_zeros_(v[1]);
65 goto gcd_2_1;
66 } else if (v[1] == 0) {
67 v[0] = v[0] >> lmmp_tailing_zeros_(v[0]);
68 goto gcd_2_1;
69 }
70 k = lmmp_tailing_zeros_(v[0]);
71 // k > 0
72 _u128lshr(v, v, k);
73 } else {
74 _u128sub(u, u, v);
75 if (u[0] == 0) {
76 u[0] = u[1] >> lmmp_tailing_zeros_(u[1]);
77 goto gcd_1_2;
78 } else if (u[1] == 0) {
79 u[0] = u[0] >> lmmp_tailing_zeros_(u[0]);
80 goto gcd_1_2;
81 }
82 k = lmmp_tailing_zeros_(u[0]);
83 // k > 0
84 _u128lshr(u, u, k);
85 }
86 }
87 dst[0] = u[0];
88 dst[1] = u[1];
89 if (cnt > 0)
90 _u128lshl(dst, dst, cnt);
91 return 2;
92
93 gcd_1_2: // [u,1] , [v,2]
94 k = lmmp_tailing_zeros_(v[0]);
95 if (k > 0)
96 _u128lshr(v, v, k);
97 while (v[1] != 0) {
98 _u128sub64(v, v, u[0]);
99 if (v[1] == 0)
100 goto gcd_1_1;
101 if (v[0] == 0) {
102 v[0] = v[1] >> lmmp_tailing_zeros_(v[1]);
103 goto gcd_1_1;
104 }
105 k = lmmp_tailing_zeros_(v[0]);
106 // k > 0
107 _u128lshr(v, v, k);
108 }
109 goto gcd_1_1;
110
111 gcd_2_1: // [u,2] , [v,1]
112 k = lmmp_tailing_zeros_(u[0]);
113 if (k > 0)
114 _u128lshr(u, u, k);
115 while (u[1] != 0) {
116 _u128sub64(u, u, v[0]);
117 if (u[1] == 0)
118 goto gcd_1_1;
119 if (u[0] == 0) {
120 u[0] = u[1] >> lmmp_tailing_zeros_(u[1]);
121 goto gcd_1_1;
122 }
123 k = lmmp_tailing_zeros_(u[0]);
124 // k > 0
125 _u128lshr(u, u, k);
126 }
127 goto gcd_1_1;
128
129 gcd_1_1: // [u,1] , [v,1]
130 while (u[0] != v[0]) {
131 if (u[0] > v[0]) {
132 u[0] -= v[0];
133 u[0] >>= lmmp_tailing_zeros_(u[0]);
134 } else {
135 v[0] -= u[0];
136 v[0] >>= lmmp_tailing_zeros_(v[0]);
137 }
138 }
139 dst[0] = u[0];
140 dst[1] = 0;
141 if (cnt > 0)
142 _u128lshl(dst, dst, cnt);
143 return dst[1] == 0 ? 1 : 2;
144}
#define _u128lshl(x, y, n)
Definition longlong.h:244
#define _u128sub(r, x, y)
Definition longlong.h:282
#define _u128cmp(x, y)
Definition longlong.h:280
#define _u128lshr(x, y, n)
Definition longlong.h:250
#define _u128sub64(r, x, _i64)
Definition longlong.h:272
mp_limb_t lmmp_gcd_11_(mp_limb_t u, mp_limb_t v)
计算 [numa,na] 在B^n 下的逆元
Definition gcd_1.c:10

引用了 _u128cmp, _u128lshl, _u128lshr, _u128sub, _u128sub64, k, lmmp_gcd_11_(), lmmp_param_assert , 以及 lmmp_tailing_zeros_().

被这些函数引用 lmmp_gcd_2_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_gcd_2_()

mp_size_t lmmp_gcd_2_ ( mp_ptr  dst,
mp_srcptr  up,
mp_size_t  un,
mp_srcptr  vp 
)

计算两个无符号整数的最大公约数

参数
up第一个无符号整数指针
un第一个无符号整数的 limb 长度
vp第二个无符号整数指针,长度为 2
dst结果指针(长度至少为 2,两个 limb 都会进行写入,即使最高位可能为0)
警告
up!=NULL, un>2, vp!=NULL, vp[1]!=0, dst!=NULL, eqsep(dst,[up|vp])
返回
dst 的实际 limb 长度

在文件 gcd_2.c146 行定义.

146 {
147 lmmp_param_assert(dst != NULL);
148 lmmp_param_assert(up != NULL);
149 lmmp_param_assert(vp != NULL);
150 lmmp_param_assert(un > 2);
151 lmmp_param_assert(vp[1] != 0);
152 mp_limb_t u[2] = {vp[0], vp[1]};
153 lmmp_mod_2_(up, un, u);
154 if (u[1] == 0 && u[0] == 0) {
155 dst[0] = vp[0];
156 dst[1] = vp[1];
157 return 2;
158 } else {
159 return lmmp_gcd_22_(dst, vp, u);
160 }
161}
mp_size_t lmmp_gcd_22_(mp_ptr dst, mp_srcptr up, mp_srcptr vp)
计算两个无符号整数的最大公约数
Definition gcd_2.c:11
void lmmp_mod_2_(mp_srcptr numa, mp_size_t na, mp_ptr numb)
双精度数取余 (除数为2个limb)
Definition div.c:144

引用了 lmmp_gcd_22_(), lmmp_mod_2_() , 以及 lmmp_param_assert.

+ 函数调用图:

◆ lmmp_gcd_basecase_()

mp_size_t lmmp_gcd_basecase_ ( mp_ptr  dst,
mp_srcptr  up,
mp_size_t  un,
mp_srcptr  vp,
mp_size_t  vn 
)

计算两个无符号整数的最大公约数(不建议使用此算法,更高版本可能被彻底弃用)

参数
dst结果指针(长度至少为 min(un,vn))
up第一个无符号整数指针
un第一个无符号整数的 limb 长度
vp第二个无符号整数指针
vn第二个无符号整数的 limb 长度
警告
up!=NULL, un>0, vp!=NULL, vn>0, eqsep(dst,[up|vp]), dst!=NULL
注解
朴素的辗转相除法,与Lehmer算法具有相似的渐进时间复杂度,但Lehmer算法绝大多数场合更加优秀
返回
dst 的实际 limb 长度

在文件 gcd_basecase.c11 行定义.

11 {
12 lmmp_param_assert(un > 0 && vn > 0);
13 if (un < vn) {
14 LMMP_SWAP(up, vp, mp_srcptr);
15 LMMP_SWAP(un, vn, mp_size_t);
16 } else if (un == vn) {
17 int cmp = lmmp_cmp_(up, vp, un);
18 if (cmp < 0) {
19 LMMP_SWAP(up, vp, mp_srcptr);
20 } else if (cmp == 0) {
21 lmmp_copy(dst, up, un);
22 return un;
23 }
24 }
26#define an un
27#define bn vn
30 lmmp_copy(a, up, an);
31 lmmp_copy(b, vp, bn);
32 while (bn > 0 || (bn == 1 && b[0] == 0)) {
33 // dst = a % b;
34 lmmp_div_(NULL, dst, a, an, b, bn);
35 lmmp_copy(a, b, bn);
36 an = bn;
37 while (dst[bn - 1] == 0 && bn > 0) {
38 --bn;
39 }
40 lmmp_copy(b, dst, bn);
41 }
42 lmmp_copy(dst, a, an);
44 return an;
45#undef an
46#undef bn
47}
#define an
#define bn
mp_limb_t * mp_ptr
Definition lmmp.h:215
#define LMMP_SWAP(x, y, type)
Definition lmmp.h:352
#define lmmp_copy(dst, src, n)
Definition lmmp.h:364
const mp_limb_t * mp_srcptr
Definition lmmp.h:216
static int lmmp_cmp_(mp_srcptr numa, mp_srcptr numb, mp_size_t n)
大数比较函数(内联)
Definition lmmpn.h:1004
void lmmp_div_(mp_ptr dstq, mp_ptr dstr, mp_srcptr numa, mp_size_t na, mp_srcptr numb, mp_size_t nb)
大数除法和取模操作
Definition div.c:57
#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

引用了 an, bn, lmmp_cmp_(), lmmp_copy, lmmp_div_(), lmmp_param_assert, LMMP_SWAP, TALLOC_TYPE, TEMP_DECL , 以及 TEMP_FREE.

+ 函数调用图:

◆ lmmp_gcd_lehmer_()

mp_size_t lmmp_gcd_lehmer_ ( mp_ptr  dst,
mp_srcptr  up,
mp_size_t  un,
mp_srcptr  vp,
mp_size_t  vn 
)

计算两个无符号整数的最大公约数(Lehmer算法)

参数
dst结果指针(长度至少为 min(un,vn))
up第一个无符号整数指针
un第一个无符号整数的 limb 长度
vp第二个无符号整数指针
vn第二个无符号整数的 limb 长度
警告
up!=NULL, un>0, vp!=NULL, vn>0, eqsep(dst,[up|vp]), dst!=NULL
返回
dst 的实际 limb 长度

在文件 gcd_lehmer.c233 行定义.

233 {
234 lmmp_param_assert(un > 0 && vn > 0);
235 lmmp_param_assert(up != NULL && vp != NULL);
236 lmmp_param_assert(dst != NULL);
237
238 if (un < vn) {
239 LMMP_SWAP(up, vp, mp_srcptr);
240 LMMP_SWAP(un, vn, mp_size_t);
241 } else if (un == vn) {
242 int cmp = lmmp_cmp_(up, vp, un);
243 if (cmp == 0) {
244 lmmp_copy(dst, up, un);
245 return un;
246 } else if (cmp < 0) {
247 LMMP_SWAP(up, vp, mp_srcptr);
248 }
249 }
250 // u > v
251
253 slong x = 0, y = 0;
254
255#define an un
256#define bn vn
258 // [a,an+1] [b,bn+1]
259 // A * a_old may overlow
260 mp_ptr a = BALLOC_TYPE(an + 1, mp_limb_t);
261 mp_ptr b = BALLOC_TYPE(bn + 1, mp_limb_t);
263 mp_ptr temp = BALLOC_TYPE((an + 1) * 3, mp_limb_t);
264 ms.tp = temp;
265 ms.mp = temp + (an + 1);
266 ms.np = temp + (an + 1) * 2;
267
268 lmmp_copy(a, up, an);
269 lmmp_copy(b, vp, bn);
270
271 bool bzero = false;
272 while (bzero == false) {
273 if (an > 1 && bn == 1) {
274 dst[0] = lmmp_gcd_1_(a, an, b[0]);
275 return 1;
276 } else if (an == 1 && bn == 1) {
277 dst[0] = lmmp_gcd_11_(a[0], b[0]);
278 return 1;
279 }
280 // a > b
281 lmmp_lehmer_extract_(a, an, b, bn, &x, &y);
282 lmmp_gcd_lehmer_step_(x, y, &M);
283
284 if (M.m21 == 0) {
285 lmmp_div_(NULL, dst, a, an, b, bn);
286 lmmp_copy(a, b, bn);
287 an = bn;
288 while (dst[bn - 1] == 0 && bn > 0) {
289 --bn;
290 }
291 if (bn == 0)
292 bzero = true;
293 else
294 lmmp_copy(b, dst, bn);
295 } else {
296 bzero = lmmp_lehmer_mul_(a, &an, b, &bn, &M, &ms);
297 if ((an < bn) || (an == bn && lmmp_cmp_(a, b, an) < 0)) {
298 LMMP_SWAP(a, b, mp_ptr);
300 }
301 }
302 }
303 lmmp_copy(dst, a, an);
305 return an;
306#undef an
307#undef bn
308}
static void lmmp_gcd_lehmer_step_(slong u, slong v, mp_gcd_lehmer_t *gcd)
Definition gcd_lehmer.c:19
static bool lmmp_lehmer_mul_(mp_ptr a, mp_size_t *an, mp_ptr b, mp_size_t *bn, mp_gcd_lehmer_t *M, lehmer_stack_t *ms)
/ a \ = / A B \ * / a \ \ b / \ C D / \ b /
Definition gcd_lehmer.c:97
#define an
static void lmmp_lehmer_extract_(mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn, slong *a, slong *b)
Definition gcd_lehmer.c:54
#define bn
mp_limb_t lmmp_gcd_1_(mp_srcptr up, mp_size_t un, mp_limb_t vlimb)
计算两个无符号整数的最大公约数
Definition gcd_1.c:30
int64_t slong
Definition numth.h:38
#define TEMP_B_DECL
Definition tmp_alloc.h:75
#define BALLOC_TYPE(n, type)
Definition tmp_alloc.h:89
#define TEMP_B_FREE
Definition tmp_alloc.h:100

引用了 an, BALLOC_TYPE, bn, lmmp_cmp_(), lmmp_copy, lmmp_div_(), lmmp_gcd_11_(), lmmp_gcd_1_(), lmmp_gcd_lehmer_step_(), lmmp_lehmer_extract_(), lmmp_lehmer_mul_(), lmmp_param_assert, LMMP_SWAP, mp_gcd_lehmer_t::m21, lehmer_stack_t::mp, lehmer_stack_t::np, TEMP_B_DECL, TEMP_B_FREE , 以及 lehmer_stack_t::tp.

+ 函数调用图:

◆ lmmp_is_prime_uint_()

bool lmmp_is_prime_uint_ ( uint  n)

判断素数

参数
n待判断的数
返回
若 n 为素数,返回 true,否则返回 false

判断素数

Hashed 2-bases for n < 684630005672341 (slightly more than 2^49) Hashed 3-bases for n < 2^64

Based on Steve Worley's 2^32 example: http://www.mersenneforum.org/showthread.php?t=12209 With a 3-base encoding idea from Bradley Berg.

Copyright 2014, Dana Jacobsen dana@.nosp@m.acm..nosp@m.org

在文件 is_prime_ulong.c249 行定义.

249 {
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}
static const uint16_t dj_base49[2048]
static int miller_rabin_32(ulong a, ulong t, ulong u, uint m, _udiv64_t *binv)
static _udiv64_t _udiv64_gen(uint64_t d)
Definition longlong.h:535
uint16_t ushort
Definition numth.h:33
static int trial_div35711(ulong n)
校验是否能被3,5,7,11整除,能够整除则返回1,否则返回0
bool lmmp_is_prime_table_(uint p)
根据全局素数表判断一个数是否为素数
#define PRIME_SHORT_TABLE_N
Definition prime_table.h:32

引用了 _udiv64_gen(), dj_base49, lmmp_is_prime_table_(), miller_rabin_32(), PRIME_SHORT_TABLE_N , 以及 trial_div35711().

+ 函数调用图:

◆ lmmp_is_prime_ulong_()

bool lmmp_is_prime_ulong_ ( ulong  n)

判断素数

参数
n待判断的数
注解
如果 n 的实际值小于2^32,此函数不会调用 lmmp_is_prime_uint_, 如果你可以保证 n 的实际值小于2^32,使用 lmmp_is_prime_uint_ 将会更快
返回
若 n 为素数,返回 true,否则返回 false

在文件 is_prime_ulong.c365 行定义.

365 {
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}
static bool lmmp_is_prime_notrial_(ulong n)

引用了 lmmp_is_prime_notrial_(), lmmp_is_prime_table_(), PRIME_SHORT_TABLE_N , 以及 trial_div35711().

+ 函数调用图:

◆ lmmp_mulmod_ulong_()

ulong lmmp_mulmod_ulong_ ( ulong  a,
ulong  b,
ulong  mod,
ulongp  q 
)

计算两个无符号整数的乘积,对mod取模,商放入 q 中

参数
a第一个无符号整数
b第二个无符号整数
q商的结果指针
mod取模数
警告
a < mod, b < mod, q!=NULL
返回
余数

◆ lmmp_multinomial_()

mp_size_t lmmp_multinomial_ ( mp_ptr  dst,
mp_size_t  rn,
uint  n,
const uintp  r,
uint  m 
)

计算多项式系数

参数
dst结果指针
rn结果指针的 limb 长度
nr[i] 的总和
r需要计算的系数的数组
m系数的个数
警告
m>1, n>0
注解
多项式系数为 ( r1+r2+...+rm )! / ( r1! * r2! * ... * rm!)
返回
返回 dst 的实际 limb 长度

◆ lmmp_multinomial_size_()

mp_size_t lmmp_multinomial_size_ ( const uintp  r,
uint  m,
ulong n 
)

计算多项式系数的 limb 缓冲区长度

参数
r需要计算的系数的数组
m系数的个数
n输出变量,将会被修改为 r[i] 的总和,即r1+r2+...+rm
返回
多项式系数的 limb 缓冲区长度(比实际长度多 1-2 个 limb)
注解
多项式系数为 ( r1+r2+...+rm )! / ( r1! * r2! * ... * rm!)
警告
我们使用 ulong* n 来同时计算 r[i] 的总和,因为 n 可能超过 0xffffffff。 我们预计算 n,这不仅可以作为后续多项式系数函数的参数传入。 同时也请调用者注意判断 n 是否超过了 0xffffffff 这是 lmmp_multinomial_ 函数的限制。

◆ lmmp_nCr_()

mp_size_t lmmp_nCr_ ( mp_ptr  dst,
mp_bitcnt_t  bits,
mp_size_t  rn,
uint  n,
uint  r 
)

计算 nCr 组合数 ( nCr = n! / (r!(n-r)!) )

参数
dst结果指针
bitsnCr 的2的因子数
rn结果指针的 limb 长度
n组合数的总数
r组合数的选择数
返回
返回 dst 的实际 limb 长度
警告
r<=n/2, n<=0xffffffff, dst!=NULL, rn>0

在文件 nCr.c231 行定义.

231 {
232 lmmp_debug_assert(r <= (n / 2));
233 mp_size_t shw = bits / LIMB_BITS;
234 bits %= LIMB_BITS;
235 lmmp_zero(dst, shw);
236 if (n <= NCR_SHORT_LIMIT)
237 rn = lmmp_odd_nCr_ushort_(dst + shw, rn - shw, n, r);
238 else
239 rn = lmmp_odd_nCr_uint_(dst + shw, rn - shw, n, r);
240 if (bits > 0) {
241 dst[shw + rn] = lmmp_shl_(dst + shw, dst + shw, rn, bits);
242 rn += shw + 1;
243 rn -= dst[rn - 1] == 0;
244 } else {
245 rn += shw;
246 }
247 return rn;
248}
#define lmmp_zero(dst, n)
Definition lmmp.h:366
#define lmmp_debug_assert(x)
Definition lmmp.h:387
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 NCR_SHORT_LIMIT
Definition mparam.h:157
mp_size_t lmmp_odd_nCr_ushort_(mp_ptr restrict dst, mp_size_t rn, uint n, uint r)
Definition nCr.c:80
mp_size_t lmmp_odd_nCr_uint_(mp_ptr restrict dst, mp_size_t rn, uint n, uint r)
Definition nCr.c:160

引用了 LIMB_BITS, lmmp_debug_assert, lmmp_odd_nCr_uint_(), lmmp_odd_nCr_ushort_(), lmmp_shl_(), lmmp_zero , 以及 NCR_SHORT_LIMIT.

+ 函数调用图:

◆ lmmp_nCr_size_()

mp_size_t lmmp_nCr_size_ ( uint  n,
uint  r,
mp_bitcnt_t bits 
)

计算 nCr 组合数的 limb 缓冲区长度

参数
n组合数的总数
r组合数的选择数
bits被修改为 nCr 的2的因子数
返回
nCr 组合数的 limb 缓冲区长度(比实际长度多 1-2 个 limb)

◆ lmmp_next_prime_ulong_()

ulong lmmp_next_prime_ulong_ ( ulong  n)

大于n的下一个素数

参数
n起始点(不含)
警告
如果 n 大于等于ulong可表示最大的质数,则返回ulong_max
返回
大于n的下一个素数

在文件 is_prime_ulong.c435 行定义.

435 {
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}
static bool trial_div31(ulong n)
static bool trial_div13(ulong n)
static bool trial_div41(ulong n)
static bool trial_div29(ulong n)
static bool trial_div37(ulong n)
#define ULONG_PRIME_MAX
static bool trial_div19(ulong n)
static bool trial_div23(ulong n)
static bool trial_div17(ulong n)
#define MP_ULONG_MAX
Definition mparam.h:140
#define PRIME_SHORT_TABLE_SIZE
Definition prime_table.h:30
const ushort prime_short_table[6542]
ushort lmmp_prime_cnt16_(ushort n)
计算小于等于 n 的素数数量

引用了 lmmp_is_prime_notrial_(), lmmp_prime_cnt16_(), MP_ULONG_MAX, prime_short_table, PRIME_SHORT_TABLE_SIZE, trial_div13(), trial_div17(), trial_div19(), trial_div23(), trial_div29(), trial_div31(), trial_div35711(), trial_div37(), trial_div41() , 以及 ULONG_PRIME_MAX.

+ 函数调用图:

◆ lmmp_nPr_()

mp_size_t lmmp_nPr_ ( mp_ptr  dst,
mp_bitcnt_t  bits,
mp_size_t  rn,
ulong  n,
ulong  r 
)

计算 nPr 排列数 ( nPr = n! / (n-r)! )

参数
dst结果指针
bitsnPr 的2的因子数
rn结果指针的 limb 长度
n排列数的总数
r排列数的选择数
警告
n>=r, dst!=NULL, rn>0
返回
返回 dst 的实际 limb 长度

◆ lmmp_nPr_size_()

mp_size_t lmmp_nPr_size_ ( ulong  n,
ulong  r,
mp_bitcnt_t bits 
)

计算 nPr 排列数的 limb 缓冲区长度

参数
n排列数的总数
r排列数的选择数
bits被修改为 nPr 的2的因子数
返回
nPr 排列数的 limb 缓冲区长度(比实际长度多 1-2 个 limb)

被这些函数引用 pow_nPr_().

+ 这是这个函数的调用关系图:

◆ lmmp_odd_factorial_uint_()

mp_size_t lmmp_odd_factorial_uint_ ( mp_ptr  dst,
mp_size_t  rn,
uint  n 
)

计算 n! 阶乘的奇数部分

参数
dst结果指针
rn结果指针的 limb 长度(factorial_size_ 函数的返回值 - bits/LIMB_BITS)
n阶乘的阶数
警告
n>0xffff, dst!=NULL, rn>0
返回
返回 dst 的实际 limb 长度

◆ lmmp_odd_nCr_uint_()

mp_size_t lmmp_odd_nCr_uint_ ( mp_ptr  dst,
mp_size_t  rn,
uint  n,
uint  r 
)

计算 nCr 组合数的奇数部分

参数
dst结果指针
rn结果指针的 limb 长度
n组合数的总数
r组合数的选择数
返回
返回 dst 的实际 limb 长度
警告
r<=n/2, 0xffff<n, dst!=NULL, rn>0

◆ lmmp_odd_nCr_ushort_()

mp_size_t lmmp_odd_nCr_ushort_ ( mp_ptr  dst,
mp_size_t  rn,
uint  n,
uint  r 
)

计算 nCr 组合数的奇数部分

参数
dst结果指针
rn结果指针的 limb 长度
n组合数的总数
r组合数的选择数
返回
返回 dst 的实际 limb 长度
警告
r<=n/2, n<=0xffff, dst!=NULL, rn>0

◆ lmmp_odd_nPr_uint_()

mp_size_t lmmp_odd_nPr_uint_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  n,
ulong  r 
)

计算 nPr 排列数的奇数部分

参数
dst结果指针
rn结果指针的 limb 长度(nPr_size_ 函数的返回值 - bits/LIMB_BITS)
n排列数的总数
r排列数的选择数
警告
0xffffffff>=n>=r, dst!=NULL, rn>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 _odd_nPr_().

+ 这是这个函数的调用关系图:

◆ lmmp_odd_nPr_ulong_()

mp_size_t lmmp_odd_nPr_ulong_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  n,
ulong  r 
)

计算 nPr 排列数的奇数部分

参数
dst结果指针
rn结果指针的 limb 长度(nPr_size_ 函数的返回值 - bits/LIMB_BITS)
n排列数的总数
r排列数的选择数
警告
n>=r, dst!=NULL, rn>0
返回
返回 dst 的实际 limb 长度

◆ lmmp_odd_nPr_ushort_()

mp_size_t lmmp_odd_nPr_ushort_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  n,
ulong  r 
)

计算 nPr 排列数的奇数部分

参数
dst结果指针
rn结果指针的 limb 长度(nPr_size_ 函数的返回值 - bits/LIMB_BITS)
n排列数的总数
r排列数的选择数
警告
0xffff>=n>=r, dst!=NULL, rn>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 _odd_nPr_(), lmmp_factorial_(), lmmp_odd_multinomial_ushort_() , 以及 lmmp_odd_nCr_ushort_().

+ 这是这个函数的调用关系图:

◆ lmmp_pow_()

mp_size_t lmmp_pow_ ( mp_ptr  dst,
mp_size_t  rn,
mp_srcptr  base,
mp_size_t  n,
ulong  exp 
)

计算大整数幂 [dst,rn] = [base,n] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
n底数的 limb 长度
exp指数
警告
n>0, base[n-1]!=0, sep(dst,base), exp>0
返回
返回 dst 的实际 limb 长度

◆ lmmp_pow_1_()

mp_size_t lmmp_pow_1_ ( mp_ptr  dst,
mp_size_t  rn,
mp_limb_t  base,
ulong  exp 
)

计算幂次方 [dst,rn] = [base,1] ^ exp

参数
dst结果指针
base底数
exp指数
警告
base>=1, exp>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 lmmp_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_pow_1_size_()

static mp_size_t lmmp_pow_1_size_ ( mp_limb_t  base,
ulong  exp 
)
inlinestatic

计算幂次方需要的limb缓冲区长度 base ^ exp

参数
base底数
exp指数
警告
exp>0, base>=1
返回
返回值为 base^exp 需要的 limb 缓冲区长度(比实际长度多 1-2 个limb)

在文件 numth.h264 行定义.

264 {
265 lmmp_param_assert(base >= 1);
266 lmmp_param_assert(exp > 0);
267 return (ceil((double)(exp)*log2((double)base)) + LIMB_BITS - 1) / LIMB_BITS + 2; /* more two limbs */
268}

引用了 LIMB_BITS , 以及 lmmp_param_assert.

被这些函数引用 lmmp_nPr_size_() , 以及 pow_nPr_().

+ 这是这个函数的调用关系图:

◆ lmmp_pow_basecase_()

mp_size_t lmmp_pow_basecase_ ( mp_ptr  dst,
mp_size_t  rn,
mp_srcptr  base,
mp_size_t  n,
ulong  exp 
)

计算奇数次幂算法 [dst,rn] = [base,n] ^ exp

参数
dst结果指针
rndst 的 limb 缓冲区长度
base底数指针
n底数的 limb 长度
exp指数
警告
n>0, base[n-1]!=0, sep(dst,base), [base,n]>1, exp>=3, exp%2==1
返回
返回 dst 的实际 limb 长度

被这些函数引用 lmmp_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_pow_size_()

static mp_size_t lmmp_pow_size_ ( mp_srcptr  base,
mp_size_t  n,
ulong  exp 
)
inlinestatic

计算幂次方需要的limb缓冲区长度 [base,n] ^ exp

参数
base底数指针
n底数 limb 长度
exp指数
警告
n>0, base[n-1]!=0, [base,n]>1
返回
返回值为 [base,n]^exp 需要的 limb 缓冲区长度(比实际长度多 1-2 个limb)

在文件 numth.h250 行定义.

250 {
251 lmmp_param_assert(n > 0);
252 lmmp_param_assert(base[n - 1] != 0);
253 mp_size_t rn = exp * (n - 1) * LIMB_BITS + ceil((double)exp * log2(base[n - 1]));
254 return (rn + LIMB_BITS - 1) / LIMB_BITS + 2; /* more two limbs */
255}

引用了 LIMB_BITS , 以及 lmmp_param_assert.

被这些函数引用 lmmp_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_pow_win2_()

mp_size_t lmmp_pow_win2_ ( mp_ptr  dst,
mp_size_t  rn,
mp_srcptr  base,
mp_size_t  n,
ulong  exp 
)

计算幂次方2比特窗口快速幂算法 [dst,rn] = [base,n] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
n底数的 limb 长度
exp指数
警告
n>0, base[n-1]!=0, sep(dst,base), exp>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 lmmp_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_powmod_uint_()

uint lmmp_powmod_uint_ ( uint  base,
ulong  exp,
uint  mod 
)

计算 base^exp 对 mod 取模

参数
base底数
exp指数
mod模数
警告
base < mod, mod > 1
返回
base^exp 对 mod 取模的结果

在文件 is_prime_ulong.c98 行定义.

98 {
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}
static uint64_t _udiv64by64_q_preinv(uint64_t numer, const _udiv64_t *denom)
Definition longlong.h:541

引用了 _udiv64_gen(), _udiv64by64_q_preinv() , 以及 lmmp_param_assert.

被这些函数引用 lmmp_powmod_ulong_().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ lmmp_powmod_ulong_()

ulong lmmp_powmod_ulong_ ( ulong  base,
ulong  exp,
ulong  mod 
)

计算 base^exp 对 mod 取模

参数
base底数
exp指数
mod模数
警告
base < mod, mod > 1
返回
base^exp 对 mod 取模的结果

在文件 is_prime_ulong.c121 行定义.

121 {
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}
static ulong mont64_R2(ulong m)
#define MONT63_MAX
static ulong to_mont63(ulong x, ulong R2, ulong m, ulong m_inv)
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 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 to_mont64(ulong x, ulong R2, ulong m, ulong m_inv)
#define MP_UINT_MAX
Definition mparam.h:139
ulong lmmp_binvert_ulong_(ulong a)
计算 a 在2^64下的逆元
Definition binvert_1.c:33

引用了 from_mont63(), from_mont64(), lmmp_binvert_ulong_(), lmmp_powmod_uint_(), MONT63_MAX, mont63_mul(), mont63_R2(), mont64_mul(), mont64_R2(), MP_UINT_MAX, to_mont63() , 以及 to_mont64().

+ 函数调用图:

◆ lmmp_prev_prime_ulong_()

ulong lmmp_prev_prime_ulong_ ( ulong  n)

小于等于n的上一个素数

参数
n起始点(含)
警告
如果 n 小于2,则返回 0
返回
小于等于n的上一个素数,如果n恰好为素数,则返回 n

在文件 is_prime_ulong.c465 行定义.

465 {
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 ULONG_PRIME_MIN

引用了 lmmp_is_prime_notrial_(), lmmp_prime_cnt16_(), prime_short_table, PRIME_SHORT_TABLE_N, trial_div13(), trial_div17(), trial_div19(), trial_div23(), trial_div29(), trial_div31(), trial_div35711(), trial_div37(), trial_div41() , 以及 ULONG_PRIME_MIN.

+ 函数调用图:

◆ lmmp_remove_()

mp_size_t lmmp_remove_ ( mp_ptr  np,
mp_size_t nn,
mp_srcptr  dp,
mp_size_t  dn 
)

除去[np,nn]中的[dp,dn]的因子

参数
np被除数指针,将会被修改为除去因子后的数
nn被除数指针的 limb 长度,将会被修改除去因子后的长度
dp除数指针
dn除数指针的 limb 长度
警告
np!=NULL, nn>0, dp!=NULL, dn>0
注解
如果[np,nn]能被[dp,dn]整除,则[np,nn]将被修改为除去因子后的数,nn将被修改为除去因子后的长度。 如果不能被整除,则[np,nn]保持不变,并返回0。
返回
[np,nn]中被[dp,dn]除去的因子的个数,如果不能被整除,则返回0

在文件 remove.c56 行定义.

56 {
57 lmmp_param_assert(np != NULL && *nn > 0);
58 lmmp_param_assert(dp != NULL && dn > 0);
59
60 mp_srcptr pd_pow[MAX_EXP];
61 mp_size_t pn_pow[MAX_EXP];
62 // qp as quotient, rp as remainder, divp as divdend
63 mp_ptr qp, rp, divp;
64 mp_ptr prod;
65 mp_size_t divn = *nn, qn;
66 mp_size_t ret = 0;
67 int i, j;
68 pd_pow[0] = dp;
69 pn_pow[0] = dn;
70
72
73 qp = TALLOC_TYPE(*nn, mp_limb_t);
74 rp = TALLOC_TYPE(*nn, mp_limb_t);
75
76 divp = np;
77
78 for (i = 1; i < MAX_EXP; i++) {
79 // if qn == 0, means cannot be divided by pd_pow[i - 1]
80 if (qn = try_div_(qp, rp, divp, divn, pd_pow[i - 1], pn_pow[i - 1])) {
81 divn = qn;
82 LMMP_SWAP(qp, divp, mp_ptr);
83
84 ret += 1 << (i - 1);
85 pn_pow[i] = 2 * pn_pow[i - 1];
86 if (divn < pn_pow[i]) {
87 ++i;
88 break;
89 }
90 prod = TALLOC_TYPE(pn_pow[i], mp_limb_t);
91 lmmp_sqr_(prod, pd_pow[i - 1], pn_pow[i - 1]);
92 pn_pow[i] -= (prod[pn_pow[i] - 1] == 0) ? 1 : 0;
93 pd_pow[i] = prod;
94 } else {
95 break;
96 }
97 }
98 for (j = i - 1; j > 0; --j) {
99 if (qn = try_div_(qp, rp, divp, divn, pd_pow[j - 1], pn_pow[j - 1])) {
100 divn = qn;
101 LMMP_SWAP(qp, divp, mp_ptr);
102
103 ret += 1 << (j - 1);
104 }
105 }
106 if (qn == 0) {
107 // 无法整除
108 lmmp_copy(np, divp, divn);
109 *nn = divn;
110 } else {
111 // 整除
112 lmmp_copy(np, qp, qn);
113 *nn = qn;
114 }
115
116 TEMP_FREE;
117 return ret;
118}
void lmmp_sqr_(mp_ptr dst, mp_srcptr numa, mp_size_t na)
大数平方操作 [dst,2*na] = [numa,na]^2
Definition sqr.c:10
static mp_size_t try_div_(mp_ptr qp, mp_ptr rp, mp_srcptr divp, mp_size_t divn, mp_srcptr numb, mp_size_t nb)
qp 为商,rp 为余数,divp 为被除数,divn 为被除数长度,numb 为除数,nb 为除数长度 如果无法整除,则返回0,否则返回除数 qp 的长度
Definition remove.c:26
#define MAX_EXP
Definition remove.c:20

引用了 lmmp_copy, lmmp_param_assert, lmmp_sqr_(), LMMP_SWAP, MAX_EXP, TALLOC_TYPE, TEMP_DECL, TEMP_FREE , 以及 try_div_().

+ 函数调用图:

◆ lmmp_trialdiv_()

ushortp lmmp_trialdiv_ ( mp_srcptr  np,
mp_size_t  nn,
ushort  N,
ushort rn 
)

试除法

参数
num被除数
nn被除数的 limb 长度
N试除法尝试的质数最大值
rn结果指针的 limb 长度
警告
num!=NULL, nn>0, N>2, rn!=NULL
注解
试除法尝试从 2-N 中所有质数进行试除,如果能整除则会插入到返回结果数组中,没有整除的则会返回 NULL。
返回
结果指针,返回不超过N,且能整除[np,nn]的素数(从小到大排列),若没有能够整除的素数,则返回NULL

◆ lmmp_u16_pow_1_()

mp_size_t lmmp_u16_pow_1_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  base,
ulong  exp 
)

计算幂次方 [dst,rn] = [base,1] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
exp指数
警告
0<base<=0xffff, exp>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 _odd_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_u32_pow_1_()

mp_size_t lmmp_u32_pow_1_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  base,
ulong  exp 
)

计算幂次方 [dst,rn] = [base,1] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
exp指数
警告
0<base<=2^32-1, exp>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 _odd_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_u4_pow_1_()

mp_size_t lmmp_u4_pow_1_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  base,
ulong  exp 
)

计算幂次方 [dst,rn] = [base,1] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
exp指数
警告
1<=base<=0xf, exp>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 _odd_pow_().

+ 这是这个函数的调用关系图:

◆ lmmp_u64_pow_1_()

mp_size_t lmmp_u64_pow_1_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  base,
ulong  exp 
)

计算幂次方 [dst,rn] = [base,1] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
exp指数
警告
2^32<=base<=2^64-1, exp>0
返回
返回 dst 的实际 limb 长度

◆ lmmp_u8_pow_1_()

mp_size_t lmmp_u8_pow_1_ ( mp_ptr  dst,
mp_size_t  rn,
ulong  base,
ulong  exp 
)

计算幂次方 [dst,rn] = [base,1] ^ exp

参数
dst结果指针
rn结果 limb 长度
base底数
exp指数
警告
0<base<=0xff, exp>0
返回
返回 dst 的实际 limb 长度

被这些函数引用 _odd_pow_().

+ 这是这个函数的调用关系图: