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

C語言隨機數生成詳解:rand()、srand()、種子與均勻分布實作

     編輯:C 語言問答

原始代碼錯誤分析


#include <stdio.h>
#include <stdlib.h>
main() {
    int i, roll[7] = {0}, m;
    for (i = 0; i < 6000; i++) {
        m = (int)(1 + rand(6));  // 錯誤:rand() 不接受參數
        roll[m]++;
    }
    for (i = 1; i <= 6; i++)
        printf("roll[%d]=%5d\n", i, roll[i]);
    return 0;
}

錯誤訊息:error C2660: 'rand' : function does not take 1 parameters

核心知識點

函數原型說明
rand()int rand(void)返回 0 到 RAND_MAX (至少 32767) 之間的偽隨機整數,無參數
srand()void srand(unsigned int seed)設定隨機數生成器種子,程式啟動時呼叫一次

正確生成 1-6 均勻隨機數


#include <stdio.h>
#include <stdlib.h>
#include <time.h>  // time() 需要

int main() {
    int roll[7] = {0};  // 索引 1-6 對應骰子點數,0 不用
    int i, m;

    // 1. 設定種子:使用當前時間,每次執行序列不同
    srand((unsigned int)time(NULL));

    // 2. 生成 6000 次
    for (i = 0; i < 6000; ++i) {
        // rand() % 6 產生 0-5,+1 變 1-6
        m = rand() % 6 + 1;  
        roll[m]++;
    }

    // 3. 輸出統計
    for (i = 1; i <= 6; ++i) {
        printf("roll[%d] = %d\n", i, roll[i]);
    }
    return 0;
}

關鍵細節解析

1. 為何需要 srand(time(NULL))?

  • rand() 產生的是偽隨機序列,由種子決定。
  • 未呼叫 srand 時,預設種子為 1,每次執行產生相同序列。
  • time(NULL) 返回當前 Unix 時間戳(秒),每秒變化,適合作種子。
  • 只呼叫一次,通常在 main 開頭。重複呼叫會重置序列,降低隨機性。

2. rand() % 6 + 1 的分布特性

  • RAND_MAX 通常為 32767 (2^15-1) 或 2147483647 (2^31-1)。
  • 取模運算會引入微小偏差(模數不整除 RAND_MAX+1 時),但對 6 面骰子、6000 次樣本可忽略。
  • 嚴格均勻需用拒絕採樣:

int uniform_d6() {
    int x;
    do {
        x = rand();
    } while (x >= RAND_MAX - (RAND_MAX + 1) % 6);  // 拒絕多餘範圍
    return x % 6 + 1;
}

3. 陣列大小與索引

  • roll[7] 索引 0-6,使用 1-6,roll[0] 永遠為 0。
  • 輸出迴圈 i=1; i<=6 正確對應骰子點數。

進階:C11 <stdrandom.h>(提議中)與現代替代方案

C 標準庫 rand/srand 品質較低(線性同餘法、週期短、低位隨機性差)。現代專案建議:

方案特點適用場景
Mersenne Twister (mt19937)週期 2^19937-1、高品質、標準 C++ <random>、C 需第三方實作科學模擬、遊戲、密碼學非敏感
PCG (Permuted Congruential Generator)狀態小、速度快、統計特性優、單檔案 C 實作嵌入式、遊戲、通用高品質
xoshiro/xoroshiro極快、高品質、並行友好、C 單頭檔高效能、並行模擬
系統熵源/dev/urandom (Linux)、BCryptGenRandom (Windows)、getrandom() (Linux 3.17+)密碼學、安全關鍵、種子生成

測試驗證:統計分布檢查


// 執行後觀察各面出現次數是否接近 1000 (6000/6)
roll[1] = 998
roll[2] = 1012
roll[3] = 987
roll[4] = 1005
roll[5] = 1003
roll[6] = 995
// 卡方檢定可量化驗證均勻性

常見錯誤對照表

錯誤代碼問題修正
rand(6)rand 無參數rand() % 6 + 1
無 srand每次執行相同序列srand(time(NULL)) 在 main 開頭呼叫一次
迴圈中呼叫 srand重置種子,序列退化移出迴圈,僅呼叫一次
rand() % n 當 n 較大模偏差明顯用拒絕採樣或高品質 RNG
roll[6] 索引 0-5輸出迴圈易混淆roll[7] 索引 1-6 對應業務語意

總結

rand() 無參數,配合 srand(time(NULL)) 初始化種子,用 rand() % n + offset 映射到目標範圍。理解偽隨機本質、種子管理、模偏差,能寫出正確、可重現、統計特性可接受的隨機數代碼。生產級高品質需求請用 PCG、xoshiro 或系統熵源。

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