首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言問答

C語言隨機數生成:srand/rand 原理、陷阱與現代替代方案

     編輯:C 語言問答

rand() / srand() 完全指南:從原理到工程級用法

基本用法

#include <stdlib.h>
#include <time.h>

int main() {
    srand((unsigned)time(NULL));  // 種子:當前時間秒數
    for (int i = 0; i < 10; ++i)
        printf("%d ", rand() % 100);  // 0-99
    return 0;
}

核心機制

  • rand():線性同餘生成器 (LCG),返回 0 到 RAND_MAX (至少 32767) 偽隨機數。
  • srand(seed):設置種子,**相同種子產生完全相同序列** (可復現調試)。
  • 不調用 srand:默認種子為 1,每次運行結果相同。
  • 全局狀態:rand() 非線程安全,多線程競爭種子/狀態。

常見陷阱與修正

錯誤寫法問題修正
rand() % N模數偏差:RAND_MAX+1 不能被 N 整除,低位數字概率略高拒絕採樣或用浮點縮放 (int)(rand() / (RAND_MAX+1.0) * N)
循環中反覆 srand(time(NULL))同一秒內種子相同,產生相同序列**程序啟動時只調用一次 srand**
多線程共用 rand()數據競爭,序列混亂用 rand_r(&seed) (POSIX) 或 C++11 std::mt19937 線程局部引擎
加密/安全場景用 rand()可預測,非加密安全用 /dev/urandom, CryptGenRandom, getrandom(), arc4random()

現代 C/C++ 最佳實踐

C11 線程安全:rand_r

unsigned int seed = (unsigned)time(NULL);
int r = rand_r(&seed);  // 線程局部種子,無全局狀態

C++11 (強烈推薦 C++ 項目)

#include 
std::mt19937 gen(std::random_device{}());  // 硬體熵源種子
std::uniform_int_distribution dist(0, 99);
for (int i=0; i<10; ++i) std::cout << dist(gen) << ' ';
// 支援正態、泊松、指數等多種分佈,極快、高質量、線程安全

C 語言高質量替代:PCG / Xorshift / SplitMix64 (單文件引入)

// SplitMix64 極簡實現
static uint64_t sm64_state;
uint64_t splitmix64() {
    uint64_t z = (sm64_state += 0x9e3779b97f4a7c15ULL);
    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
    return z ^ (z >> 31);
}
void sm64_seed(uint64_t s) { sm64_state = s; }

工程建議

  1. **測試/模擬可復現**:固定種子 srand(12345) 或 mt19937 gen(12345)。
  2. **均勻分佈**:優先用 uniform_int_distribution 或拒絕採樣,避免 %N 偏差。
  3. **並發**:每線程獨立引擎/種子,避免鎖競爭。
  4. **安全**:密鑰、Token、Session ID 必須用 CSPRNG (系統提供)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved