rand() 產生的是偽隨機數列 — 由確定性演算法根據初始種子生成。相同種子產生相同序列。這在除錯時是優點 (可重現),在正式環境是缺點 (可預測)。本文涵蓋標準用法、常見錯誤、進階技巧與現代替代方案。
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void) {
int m, n;
time_t t;
// 1. 初始化種子 (僅呼叫一次!)
srand((unsigned)time(&t));
// 2. 產生隨機數
m = rand(); // 0 ~ RAND_MAX (至少 32767)
n = rand() % 10; // 0 ~ 9
printf("m = %d\nn = %d\n", m, n);
return 0;
}
time_t time(time_t *timer);
NULL 可忽略輸出參數:time(NULL)void srand(unsigned int seed);
main() 開頭time(NULL) — 最常用getpid() — 進程 ID,同一程式多次執行不同time(NULL) ^ getpid() — 結合時間與 PID,熵值較高rdtsc() / clock_gettime() — 高精度時間 (平台相關)0 ~ RAND_MAX (標準保證 ≥ 32767,實際常為 2147483647)next = (next * 1103515245 + 12345) & 0x7fffffffrand_r() 或 C++11 <random>| 需求 | 寫法 | 備註 |
|---|---|---|
| [0, N-1] | rand() % N | 簡單但有模數偏差 |
| [M, N] | M + rand() % (N - M + 1) | 包含邊界 |
| [0.0, 1.0) | (double)rand() / RAND_MAX | 浮點數 |
| 無偏差均勻分布 | 見下文 | 拒絕採樣法 |
rand() % N 當 RAND_MAX+1 不能整除 N 時,低數值機率略高。
// 無偏差版本:拒絕採樣
int rand_unbiased(int n) {
int limit = RAND_MAX - (RAND_MAX % n);
int r;
do {
r = rand();
} while (r >= limit);
return r % n;
}
int rand_r(unsigned int *seedptr);
#include <random>
#include <iostream>
int main() {
// 1. 隨機裝置 (硬體熵源,非確定性)
std::random_device rd;
// 2. 梅森旋轉演算法引擎 (高品質、週期 2^19937-1)
std::mt19937 gen(rd());
// 3. 分布適配器
std::uniform_int_distribution<> dis(1, 100); // [1, 100] 均勻分布
std::normal_distribution<> ndis(0.0, 1.0); // 常態分布
// 4. 使用
for (int i = 0; i < 5; ++i) {
std::cout << dis(gen) << ' ';
}
// 輸出範例:42 87 13 95 6
}
std::random_device 或 OS 提供的 /dev/urandom, CryptGenRandomsrand(time(NULL) ^ getpid()) + rand(),注意模數偏差rand_r() 或獨立種子rand()std::random_device 或平台 CSPRNGsrand(12345) 或 std::mt19937 gen(12345)rand()/srand() 是 C 語言的歷史遺產,理解其「偽隨機、全域狀態、品質有限」本質至關重要。現代 C++ 專案請毫不猶豫拥抱 <random>,獲得統計品質優異、執行緒安全、分布靈活的隨機數生成能力。記住:**永遠不要用 rand() 做密碼學用途**。