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

C 語言隨機數生成完全指南:rand/srand 進階用法與避坑

     編輯:關於C

C 語言隨機數生成完全指南:rand/srand 進階用法與避坑

C 標準庫提供 rand()/srand() 生成偽隨機數,本文系統講解種子機制、範圍控制、不重複隨機數生成等實戰技巧。

核心概念

  • 偽隨機:按確定性算法生成,同一種子產生相同序列
  • RAND_MAX:rand() 最大返回值(至少 32767)
  • 種子:srand(seed) 設置初始狀態,未調用默認種子為 1

基本用法

#include 
#include 
#include 

int main() {
    // 以當前時間作種子,每次運行序列不同
    srand((unsigned)time(NULL));

    // 生成 10 個 0~RAND_MAX 隨機數
    for (int i = 0; i < 10; i++)
        printf("%d\n", rand());

    return 0;
}

常見範圍映射公式

需求公式示例
[0, 1] 浮點數rand() / (RAND_MAX + 1.0)printf("%.4f", rand()/32768.0);
[min, max] 整數rand() % (max - min + 1) + minrand() % 100 + 1 → [1,100]
[0, n-1] 整數rand() % nrand() % 10 → [0,9]

MSDN 推薦的高質量映射(均勻分佈)

// 生成 [RANGE_MIN, RANGE_MAX] 區間隨機數
int RANGE_MIN = 0, RANGE_MAX = 100;
int rand100 = (int)(((double)rand() / (RAND_MAX + 1.0)) * (RANGE_MAX - RANGE_MIN + 1) + RANGE_MIN);

避免 rand() % n 導致的分佈偏態(當 n 不能整除 RAND_MAX+1 時)。

生成不重複隨機數(洗牌算法 / Fisher-Yates)

方法一:數組洗牌

void swap(int *a, int *b) { int t=*a; *a=*b; *b=t; }

int main() {
    int a[513];
    for (int i=1; i<=512; i++) a[i] = i;  // 初始化有序數組

    srand((unsigned)time(NULL));
    for (int i=512; i>=1; i--)
        swap(&a[i], &a[rand()%i + 1]);   // 關鍵:+1 避免索引 0

    // 前 64 個即為不重複隨機數
    for (int i=1; i<=64; i++) printf("%4d", a[i]);
}

方法二:標記法(適用範圍較大、需少量數時)

int a[100] = {0};
for (int i=1; i<=99; i++) {
    int m;
    while (a[m = rand()%100 + 1]);  // 找未被佔用的槽位
    a[m] = i;                       // 標記並存入順序號
}

關鍵避坑指南

  1. 不要重複調用 srand:程序啟動時調用一次,循環中調用會導致同秒內生成相同序列
  2. 線程安全:rand() 非線程安全,多線程用 rand_r() 或 C++11 <random>
  3. 加密用途禁用:偽隨機不可用於密鑰生成,需用 /dev/urandom 或 CryptGenRandom
  4. 隨機質量:rand() 通常為線性同餘法,統計質量一般;科學計算建議用 Mersenne Twister (mt19937)

現代 C++ 替代方案

#include 
#include 

int main() {
    std::random_device rd;              // 硬件熵源
    std::mt19937 gen(rd());             // 梅森旋轉算法
    std::uniform_int_distribution<> dis(1, 100); // 均勻分佈 [1,100]

    for (int i=0; i<10; i++)
        std::cout << dis(gen) << '\n';
}

總結:srand(time(NULL)) + rand()%n 適合簡單場景;嚴格均勻分佈用浮點映射;不重複需求用洗牌算法;生產級項目優先選用 C++11 <random>。

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