1. 程式人生 > >探究rand()隨機數

探究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;
}

轉載請註明出處!!!

如果有寫的不對或者不全面的地方 可通過主頁的聯絡方式進行指正,謝謝