C++亂數(rand和srand)函數用法詳解

2020-07-16 10:04:38
C++ 提供了一組函數以生成和使用亂數字。亂數字就是從一組可能的值中進行隨機選擇而獲得的一個值。該組中的值都有相同的被選中的幾率。

亂數字常用於許多不同型別的程式中,以下是一些範例:
  • 計算機遊戲通常要使用亂數字來模擬一些隨機過程,例如擲骰子或發牌。
  • 模擬程式使用亂數字來決定後續將要發生的一系列操作或人與動物等的行為。可以建立使用亂數字的公式以確定特定事件在程式中出現的時間。
  • 資料分析程式可能會使用亂數字隨機選擇要檢驗的資料。
  • 電腦保安系統使用亂數字來加密敏感資料。

C++ 庫有一個名為 rand() 的函數,每次呼叫該函數都將返回一個非負整數。要使用 rand() 函數,必須在程式中包含 <cstdlib> 標頭檔案。以下是其用法範例:

randomNum = rand();

但是,該函數返回的數位其實是偽亂數。這意味著它們具有亂數的表現和屬性,但實際上並不是隨機的,它們實際上是用演算法生成的。

該演算法需要一個起始值,稱為種子,以生成數位。如果沒有給出一個種子,那麼它將在每次執行時產生相同的數位流。下面的程式說明了這一點:
//This program demonstrates what happens in C++ if you
// try to generate random numbers without setting a "seed".
#include <iostream>
#include <cstdlib>// Header file needed to use rand
using namespace std;

int main()
{
    // Generate and printthree random numbers
    cout << rand() << " ";
    cout << rand() << " ";
    cout << rand() << endl ;
    return 0;
}

第1次執行輸出結果:
41 18467 : 6334
第2次執行輸出結果:
41 18467 6334

要在每次執行程式時獲得不同的亂數字流,則必須為亂數生成器提供一個種子以開始。在 C++ 中,這是通過呼叫 srand 函數完成的。

在 rand 被呼叫之前,srand 函數要先被呼叫,並且 srand 在整個程式中僅被呼叫一次。
// This program demonstrates using random numbers when a
// "seed" is provided for the random number generator.
#include <iostream>
#include <cstdlib> // Header file needed to use srand and rand
using namespace std;

int main()
{
    unsigned seed;  // Random generator seed
    // Get a nseed" value from the user
    cout << "Enter a seed value: ";
    cin >> seed;
    // Set the random generator seed before calling rand()
    srand(seed);
    //Now generate and print three random numbers
    cout << rand() << " ";
    cout << rand() << " ";
    cout << rand() << endl;
    return 0;
}

第1次執行結果:
Enter a seed value: 19
100 15331 - 209
第2次執行結果:
Enter a seed value: 171
597 10689 28587

程式中,第 9 行中建立的用於儲存種子的變數 seed 被宣告為 unsigned 無符號型別。這個資料型別只儲存非負整數。這是 srand 函數在呼叫時期望接收的資料型別,因此使用 unsigned 變數型別可以保證不會將負數傳送給 srand。從程式的輸出可以看出,每次程式使用不同的種子執行時,都會生成不同的亂數字流。然而,如果再次使用 19 或 171 作為種子執行程式,則將獲得與第一次完全相同的數位。

程式的第 12 行中,使用 cin 從使用者的輸入獲取亂數生成器種子的值。實際上,獲取種子值的另一個常見做法是呼叫 time 函數,它是 C++ 標準庫的一部分。

time 函數返回從 1970 年 1 月 1 日午夜開始到現在逝去的秒數,因此每次執行程式時,它都將提供不同的種子值。下面程式演示了 time 函數的用法。請注意,在呼叫它時必須給它傳遞一個引數 0。同時程式中包含一個新的標頭檔案 ctime,此標頭檔案是使用 time 函數所必需的。
//This program demonstrates using the C++ time function
//to provide a nseed,T for the random number generator.
#include <iostream>
#include <cstdlib> // Header file needed to use srand and rand
#include <ctime> // Header file needed to use time
using namespace std;

int main()
{
    unsigned seed;  // Random generator seed
    // Use the time function to get a "seed” value for srand
    seed = time(0);
    srand(seed);
    // Now generate and print three random numbers
    cout << rand() << " " ;
    cout << rand() << " " ;
    cout << rand() << endl;
    return 0;
}
程式輸出結果:

2961 21716 181

限制亂數的範圍

有時程式需要一個特定範圍內的亂數。要將亂數的範圍限制在 1 和某個最大值 max 之間的整數,可以使用以下公式:

number = rand() % max + 1;

例如,要生成 1?6 的亂數來代表骰子的點數,則可以使用以下語句:

dice = rand() % 6 + 1;

這裡簡單介紹一下其工作原理。求餘數運算子(%)可以獲得整除之後的餘數。當使用通過 rand 函數返回的正整數除以6時,餘數將是 0?5 的數位。因為目標是 1?6 的數位,所以只需要給餘數加 1 即可。

這個想法可以擴充套件到任意範圍內的亂數,其通用公式如下:

number = (rand()%(maxValue - minValue +1)) + minValue;

在上述公式中,minValue 是範圍內的最小值,而 maxValue 則是範圍內的最大值。例如,要獲得 10?18 的亂數,可以使用以下程式碼給變數 number 賦值:

const int MIN_VALUE = 10;
const int MAX_VALUE = 18;
number = rand() % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE;

在上述程式碼中,(MAX_VALUE - MIN_VALUE + 1)的值為 9,這是目標範圍內整數的個數。餘數運算子(%)返回的值是 0?8 的數位,再用它加上 MIN_VALUE(也就是 10),即可獲得 10?18 的亂數。