获取随机数一般很容易,只需要
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int i;
// 使用系统时间作为种子(初始化随机数,用于确定随机数生成器生成随机数序列的起点),确保每次运行产生不同的随机数序列,函数time返回从1970.1.1以来经历的秒数
srand(time(NULL));
for (i = 0; i < 10; i++) {
int random_num = rand();
printf("%d\n", random_num);
}
return 0;
}
本文探讨使用静态随机变量实现伪随机数生成——LCG算法
先给代码(两个文件):
// 文件:main.c
#include <stdio.h>
#include <time.h>
#define N 100
void mysrand(unsigned);
unsigned myrand();
int main() {
int i, head = 0, reverse = 0;
mysrand(time(NULL));
for (i = 0; i < N; i++)
{
if (myrand() % 2) head++;
else reverse++;
}
printf("%d%d\n", head, reverse);
return 0;
}
// 文件:rand.c
#define INITIAL_SEED 17
#define MULTIPLIER 25173
#define INCREMENT 13849
#define MODULUS 32767
static unsigned long seed = INITIAL_SEED; // 种子
unsigned myrand()
{
seed = (seed * MULTIPLIER + INCREMENT) % MODULUS;
return seed; // 0~MODULUS的随机整数
}
void mysrand(unsigned x)
{
seed = x; // 用形参x初始化随机数的种子
}
使用static定义静态随机变量可以让seed只被当前文件内的函数使用,不会被其它文件误使用。
该程序使用LCG生成随机数,依据随机数的奇偶性分配数字给printf的四位数的1,2与3,4位。其中千位与百位的“二位数”代表随机数的偶数次数,十位与个位的“二位数”代表奇数次数。
伪随机数生成算法——线性同余法(LCG Linear Congruential Generator):
式中Xn是伪随机序列,seed是种子变量,M是模数,A是乘数,C是增量。
A,C,M的选取可以多种多样,为了方便计算,一般采用M=2^k混合同余法。当M为2的幂时,可以用位运算实现模运算,提高计算效率。
M越大,均值越接近(MIN+MAX)/2(MIN与MAX视参数而定),方差越接近1/12。
线性同余法的最大周期是M,但一般情况下会小于M。要使周期达到最大,应该满足以下条件:
(1)C和M互质;(没有共同的质因子,确保在一次完整的循环中,所有取值都能够被覆盖到)
(2)M的所有质因子的积能整除A-1;(确保在一次完整的循环中,所有取值都能够被生成,以避免出现周期缩短的情况。)
(3)若M是4的倍数,则A-1也是;(为了避免周期缩短)
(4)A,C,seed都比M小;(确保生成的伪随机数在取模运算时不超过上限M)
(5)A,C是正整数。(有本事你不用正整数)
比如:设M=16,A=5,C=3,seed=2。(1)C,M互质,(2)M的所有质因子「也就是2」的积「也就是2」可以整除A-1「也就是4」,(3)(4)(5)过于显然,略。满足条件。
条件不满足的情况(4,5太简单了就不举例了):
如需证明过程,可参考文献:
[1]张广强,张小彩.混合线性同余发生器的周期分析[J].商丘师范学院学报,2007,(6): 40-42