C 標準庫 rand() 生成的是偽隨機數。它以種子為初始值,透過線性同餘法等遞推公式產生序列。序列週期極長時統計特性近似隨機。預設種子為 1,導致程式每次執行輸出相同。必須用 srand() 設定種子打破確定性。
srand() + rand()#include <stdlib.h>
#include <time.h>
srand((unsigned)time(NULL)); // 以當前時間為種子
int r = rand(); // 0 ~ RAND_MAX (>=32767)
關鍵點:srand 僅需呼叫一次,通常在 main 開頭。重複呼叫 srand 且種子相同會重置序列。
| 目標範圍 | 推薦代碼 | 原理 |
|---|---|---|
| [0, 1) 浮點數 | rand() / (RAND_MAX + 1.0) | 浮點除法歸一化 |
| [min, max] 整數 | min + rand() % (max - min + 1) | 模運算,分布略有偏差 |
| 嚴格均勻整數 | 拒絕採樣循環 | 丟棄超出完整區間的值 |
random()、randomize() 為什麼不用?random(num):直接返回 [0, num-1],方便但非 ANSI C,僅限舊版 Borland/Turbo C。randomize():自動以時間設種子,同樣非標準。rand/srand。需求:從 1~N 產生不重複隨機排列(如撲克牌洗牌、抽獎)。
// Fisher-Yates 洗牌:O(N) 時間、O(N) 空間
int a[N+1];
for (int i = 1; i <= N; ++i) a[i] = i;
for (int i = N; i >= 1; --i)
swap(&a[i], &a[rand() % i + 1]); // +1 關鍵:避免索引 0
// a[1]~a[N] 即為隨機排列
另一種「檢查法」效率極低(O(N²) 甚至無限循環),生產環境禁止使用。
srand():每次運行結果相同。srand(time(NULL)):若循環極快,種子相同導致產生相同數。char 接收 rand():rand() 返回 int,char 會截斷高位。RAND_MAX+1 不整除範圍大小導致分布不均,高精度場景用浮點縮放或拒絕採樣。rand() 非執行緒安全,C++11 應用 <random> 庫(mt19937 + 分佈器)。<random> 標準庫#include <random>
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> dist(1, 100);
int r = dist(gen); // 高質量、執行緒安全、分布完美
C++11 起強烈建議棄用 rand/srand,改用 <random> 體系。