計算機無法產生真隨機數,僅能通過確定性算法生成偽隨機序列。本文深度解析線性同餘法 (LCG) 核心算法,對比標準庫 rand/srand 實現,並提供可移植的自定義隨機數生成器代碼。
遞推公式:X_{n+1} = (a * X_n + c) mod m
m:模數(決定周期上限)a:乘數c:增量(c=0 為乘同餘法)X_0:種子滿足 Hull-Dobell 定理 條件可達到最大周期 m:
c 與 m 互質a-1 是 m 所有質因子的倍數m 為 4 的倍數,則 a-1 也是 4 的倍數| 名稱 | m | a | c | 用途 |
|---|---|---|---|---|
| glibc (ANSI C) | 2³¹ | 1103515245 | 12345 | Linux rand() 歷史實現 |
| MSVC | 2³¹ | 214013 | 2531011 | Windows rand() |
| Java Random | 2⁴⁸ | 25214903917 | 11 | java.util.Random |
| POSIX drand48 | 2⁴⁸ | 0x5DEECE66D | 0xB | 高質量雙精度 |
| Numerical Recipes | 2³² | 1664525 | 1013904223 | 科學計算推薦 |
#include#include // 全局種子狀態 static uint32_t g_rand_seed = 0; // 核心生成:返回 32 位隨機數 uint32_t my_rand(void) { // 參數同 glibc: a=1103515245, c=12345, m=2^31 // 此處用 32 位無符號自然溢出實現 mod 2^32,再取高 16 位混合 g_rand_seed = g_rand_seed * 1103515245u + 12345u; // 經典混淆:高低 16 位交換,提升低位隨機性 return (g_rand_seed << 16) | ((g_rand_seed >> 16) & 0xFFFF); } // 種子初始化:使用時間 + 多次預熱 void my_srand(void) { g_rand_seed = (uint32_t)time(NULL); my_rand(); my_rand(); my_rand(); // 預熱:丟棄前幾個數 } // 獲取 [0, max) 範圍隨機數 uint32_t my_rand_range(uint32_t max) { return my_rand() % max; // 簡單取模,有輕微統計偏差,工程可用拒絕採樣優化 } int main() { my_srand(); printf("10 個 0-99 隨機數:\n"); for (int i = 0; i < 10; i++) { printf("%u ", my_rand_range(100)); } printf("\n"); return 0; }
#include#include int main() { srand((unsigned)time(NULL)); // 種子 for (int i = 0; i < 10; i++) { printf("%d ", rand() % 100); // RAND_MAX 通常 32767 或 2^31-1 } printf("\n"); return 0; }
| 特性 | 自定義 LCG | 標準 rand() |
|---|---|---|
| 可移植性 | 完全可控,跨平台行為一致 | 實現定義,不同平台序列不同 |
| 線程安全 | 全局狀態,非線程安全 | 全局狀態,非線程安全 (C11 有 rand_r) |
| 隨機質量 | 可選高質量參數集 | 通常較差 (LCG 低位周期短) |
| 加密安全 | 否 | 否 |
rand_r(&seed) 線程安全版,或自定義 LCG/xorshift。xorshift64*、PCG、SplitMix64(無狀態、極快、統計優)。/dev/urandom (Linux)、BCryptGenRandom (Windows)、getrandom() (Linux 3.17+)、arc4random() (BSD)。std::mt19937 (梅森旋轉) + std::uniform_int_distribution,標準庫首選。static uint64_t g_xorshift_state = 1;
uint64_t xorshift64star(void) {
uint64_t x = g_xorshift_state;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
g_xorshift_state = x;
return x * 0x2545F4914F6CDD1Dull; // 乘法混淆輸出
}
void xorshift_seed(uint64_t seed) {
g_xorshift_state = seed ? seed : 1; // 狀態不能為 0
}
理解偽隨機數的數學本質、參數選擇權衡、標準庫局限性,是編寫可復現測試、模擬系統、遊戲邏輯、非加密協議的基礎能力。嚴禁在密碼學場景使用 LCG/rand/xorshift,必須使用 CSPRNG。