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

C語言 rand() 偽隨機函數週期深度測試:Windows vs Linux、取模影響分析

     編輯:關於C語言

C語言 rand() 偽隨機函數週期深度測試:Windows vs Linux、取模影響分析

rand() 是 C 標準庫提供的偽隨機數生成器,內部演算法實作由編譯器決定(通常為線性同餘法 LCG)。本文透過實測驗證其週期(G點)、跨平台差異,以及二次取模運算是否影響週期長度。

測試方法論

  1. 先產生 _INT_R 筆基準隨機序列存入陣列 rbase。
  2. 持續呼叫 rand(),每次與 rbase[0] 比對,若相同則進入逐項比對後續 _INT_R-1 筆。
  3. 全數匹配即判定找到週期,記錄總呼叫次數。
  4. 為加速測試,每 _INT_FZ 次輸出進度。

Windows (VS2015, x64 Release) 測試結果

_INT_R (比對長度)偵測到的週期換算公式
1282,147,483,7762,147,483,776 - 128 = 2,147,483,648
10242,147,484,6722,147,484,672 - 1024 = 2,147,483,648

結論:Windows VS2015 rand() 週期為 231 = 2,147,483,648。

Linux (Ubuntu VM, gcc -O3) 測試結果

同樣邏輯跑數小時仍未偵測到週期,推測 glibc 實作週期極長(可能 264 級別),或採用更複雜演算法(如 Mersenne Twister 變體)。虛擬機效能較差,建議實體機長跑或改用統計檢測套件(TestU01、Dieharder)。

二次取模 rand() % N 是否改變週期?

修改測試程式將 rand() 回傳值先 % 100 再比對,結果 週期完全不變(仍為 2,147,483,648)。

推論:rand() 內部狀態遞迴與輸出值映射分離,取模僅為輸出端映射,不影響內部狀態機週期。

實用區間隨機函數 random(min, max)


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

/* 回傳 [min, max] 閉區間隨機整數 */
int random(int min, int max) {
    assert(min < max);
    return rand() % (max - min + 1) + min;
}

int main() {
    srand((unsigned)time(NULL));  /* 僅程式啟動時呼叫一次 */
    for (int i = 0; i < 100; i++) {
        printf("%3d ", random(-5, 5));
        if ((i + 1) % 10 == 0) putchar('\n');
    }
    return 0;
}

最佳實務總結

  1. 種子初始化:srand(time(NULL)) 僅在 main 開頭呼叫一次,切勿重複呼叫導致序列重置。
  2. 取模偏差:rand() % N 當 RAND_MAX 非 N 倍數時,低位數分布略有偏差。高品質需求可用拒絕採樣或 random()/arc4random()。
  3. 執行緒安全:rand() 非執行緒安全,多執行緒請用 rand_r() 或 C++11 <random>。
  4. 加密用途:嚴禁用 rand(),請改用 /dev/urandom、getrandom() 或 OpenSSL RAND_bytes。

了解 rand() 週期與特性,有助於在遊戲掉寶、抽獎、模擬等場景做正確技術選型。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved