探究rand()随机数

关于srand()函数

​ srand()函数用于设置随机种子,一般参数为time(0)作为随机种子

关于time()函数

​ time(0)函数返回当前时间戳(以秒为单位,从1900.01.01开始,时间戳是32位整数,所以2036年就会失效)

####关于rand()函数

​ rand()会随机生成一个整型(实质是一套算法,若种子相同,一套算法算出来的东西也相同)

关于rand()函数的随机性

​ 由于rand()函数也是一种算法,传入相同的随机种子,生成的数也是相同的,所以广义上来说,随机数并不是真正的随机,是一种伪随机。

​ 一个随机算法,需要保证在规定的范围内的每一个数都有可能出现且出现的概率是相同的,根据传入的随机种子不同,随机数也不同。

####rand()函数算法如何实现0~2^32 - 1均匀随机的出现?

​ 利用费马定理:如果p是一个素数,a^(φ§) % p = 1(当a与p互素时)

​ 具体见代码

#include <iostream>
using namespace std;
#define MAX_N 100000

//100000以内的素数数组
int prime[MAX_N + 5] = {0};

//my_seed是一个随机种子,rand()算法核心的两个参数a_num, b_num,
//利用my_seed = my_seed * a_num % b_num能够保证my_seed在1~b_num - 1均匀的出现
static int my_seed = 37, a_num, b_num;

//自定义rand()函数
int my_rand() {
#define i my_seed
    do {
        //rand()算法的核心,该算式能够保证i在1~9999均匀的出现
        i = i * a_num % b_num;
    } while (i > 10000);
    return i;
#undef i
}

//至于a_num和b_num如何得到,下面是求解过程

//预处理全部素数
void init_prime() {
    for (int i = 2; 2 * i <= MAX_N; i++) {
        if (!prime[i]) {
            prime[++prime[0]] = i;
        }
        for (int j = 1; j <= prime[0]; j++) {
            if (i * prime[j] > MAX_N) break;
            prime[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    return ;
}

//快速幂函a^b % c
int quick_mod(int a, int b, int c) {
    int ans = 1, temp = a % c;
    while (b) {
        if (b & 1) ans *= temp;
        temp *= temp;
        temp %= c;
        ans %= c;
        b >>= 1;
    }
    return ans;
}

//由于b为质数且a,b互质,根据费马定理小定理a^(φ(p)) % p = 1,也就是a^(p - 1) % p = 1
//因此我们只需要确定p - 1的全部约数不为1,即确定a^i是循环节为p - 1的算式
int get_len(int a, int b) {
    for (int i = 1; i < b - 1; i++) {
        if ((b - 1) % i) continue;
        if (quick_mod(a, i, b) == 1) return i;
    }
    return b - 1;
}


void get_a_and_b(int *a, int *b) {
    //找到一个大于13000的素数b_num
    for (int i = 1; i <= prime[0]; i++) {
        *b = prime[i];
        if (prime[i] > 13000) break;    
    }
    //根据b_num找到符合条件的a_num
    for (int i = 2; i < *b; i++) {      
        if (get_len(i, *b) != *b - 1) continue;
        *a = i;
        break;
    }
    return ;
}

//对a(也就是a_num),b(也就是b_num)进行验证
void check(int a, int b) {
    a_num = a, b_num = b;
    int vis[10001] = {0};
    for (int i = 0; i < 10000; i++) {
        int temp = my_rand();
        if (vis[temp]) {
            cout << "error" << endl;
            exit(0);
        }
        vis[temp] = 1;
    }
    cout << a << " " << b << " OK" << endl;
    return ;
}

int main() {
    init_prime();
    int a, b;
    get_a_and_b(&a, &b);
    check(a, b);
    return 0;
}

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/85546891