使用GMP库生成随机数
使用GMP库生成随机数
本文讲解使用GMP库生成随机数的方法,主要讲解gmp_randclass
的使用方法。
算法初始化
GMP库提供状态初始化一共有三种方式,底层的函数分别如下:
gmp_randinit_mt (gmp_randstate_t state)
void gmp_randinit_lc_2exp (gmp_randstate_t state, const mpz_t a, unsigned long c, mp_bitcnt_t m2exp)
int gmp_randinit_lc_2exp_size (gmp_randstate_t state, mp_bitcnt_t size)
第一种方法使用的是梅森旋转算法。使用gmp_randclass
初始化则可以写成如下代码:
1 | gmp_randclass st(gmp_randinit_mt); |
第二种方法使用的是线性同余算法,每次从旧状态\(X\)迭代出来的新状态\(X'\)满足\(X'=(aX+c) \bmod
2^{\texttt{m2exp}}\)。使用gmp_randclass
初始化则可以写成如下代码:
1 | // mpz_class a=13; |
第三种方法则是由第二种方法改进而来。同样使用线性同余算法,给定\(\mathtt{size}\),那么\(a,c,\texttt{m2exp}\)从固定的表中选择,满足\(\mathtt{m2exp\ge
size}\)。使用gmp_randclass
初始化则可以写成如下代码:
1 | // mp_bitcnt_t size = 64; |
需要注意的是,这种方法下参数size
不能大于\(128\)。
此外还有一个方法gmp_randinit_default
,这是GMP库中采用的默认初始化方法,也就是梅森旋转算法。也就是说,这个方法和gmp_randinit_mt
是完全一样的。使用gmp_randclass
初始化则可以写成如下代码:
1 | gmp_randclass st(gmp_randinit_default); |
随机数种子
gmp_randclass
中有一个方法gmp_randclass::seed()
用来给当前状态赋予随机数种子。分别接受以下两种不同类型的种子输入:
1 | void gmp_randclass::seed (unsigned long int s) |
类似的,和使用srand(time(NULL))
时一样,以time(NULL)
传入随机数参数时,也可以写成:
1 | gmp_randclass st(gmp_randinit_mt); |
产生随机数
gmp_randclass
中有三种产生整数的方法:
mpz_class gmp_randclass::get_z_bits (mp_bitcnt_t l)
mpz_class gmp_randclass::get_z_range (mpz_class n)
mpf_class gmp_randclass::get_f (mp_bitcnt_t prec)
第一种方法用于均匀产生\([0,2^{l}-1]\)中的所有\(l\)比特整数。其中入参还可以是mpz_class
类型。
第二种方法用于均匀产生\([0,n-1]\)中的所有整数。
第三种方法用于均匀产生\([0,1)\)中的所有精确到前prec
比特的小数。如果没有prec
入参,那么生成的浮点数默认精度。
示例程序
为了保证程序能够复现,这里不引入时间作为随机数种子。
1 |
|
1 |
|
1 |
|