在 C++ 中通過擲骰子生成隨機值
計算機無法猜測數字。每次機器生成一個隨機數時,它要麼是某種按位運算的乘積,要麼是數值因子(即時間、序列)的導數。
使用上述方法的問題是,如果重複足夠多次,它們將產生相同的結果集。
這就是為什麼不建議將用於生成隨機數的傳統演算法用於加密實踐的原因。結果很容易預測。
在預測隨機性時,擲骰子是一項相當簡單的任務。在本文中,讀者將瞭解計算機中的隨機性以及如何使用 C++ 從簡單的擲骰子中獲取隨機結果。
在 C++ 中通過擲骰子生成隨機數
偽隨機生成器是一種生成看似隨機的數字的機器。相反,它們是完全可以預測的。
這是因為傳統的隨機數生成器使用種子。簡單來說,種子是一個依賴於時間或數值分量的單射函式。
例如,通過在 x(0)
上重複應用內射函式(稱為 f(x0)
)為給定種子 x(0)
產生的結果,因此 fn(x0)
不同於 fn-1(x0)
或 fn+1(x0)
,其中 fn
表示函式結構 n
次。
換句話說,f(x)
包含與之前的幾乎無關的大躍遷。
種子使用時間在 C++ 中為擲骰子建立隨機數
在大多數情況下,生成的種子取決於時間因素。這意味著單射函式會考慮時鐘中的當前秒數。
讓我們看一個例子來更好地理解它。
unsigned main_seed;
main_seed = time(0);
srand(main_seed);
在這裡,一個無符號變數 main_seed
被初始化;此變數用於儲存當前時間。srand()
是一個從種子生成結果的 C++ 函式。
生成種子後,rand()
函式可以用作種子,以使用線性方程生成隨機值。
除非涉及現代 CPU,否則使用時間因子來獲取獨特的種子似乎是一種很好的做法,因為它們以納秒為單位處理程序,這會在隨機性方面破壞整個功能。
在大多數情況下,生成的種子取決於時間因素。這意味著單射函式會考慮時鐘中的當前秒數。
因為時鐘並不像人們想象的那麼快,如果 srand(time)
在一秒鐘內被多次使用,同一個種子會被多次獲得。因此,生成的隨機數集將是相似的。
這可能是一個(重大)問題,尤其是在分組密碼程式中。在後一種情況下,人們購買了大量基於實時物理形容詞的發生器,例如大氣資料中的溫度變化等,或者最近測量量子位元,例如偏振光子如何疊加的因素.
在 C++ 中使用任意數為擲骰子建立隨機數的種子
下面的示例演示了一個使用數字的偽數生成器。
static unsigned long int rand_num = 2;
int rand(void) // The ceiling limit is kept at 32767
{
rand_num = rand_num * 113546545 + 12345;
return (unsigned int)(rand_num / 65536) % 32768;
}
void srand(unsigned int main_seed) // seed is stored inside variable main_seed
{
rand_num = main_seed;
}
一個無符號整數變數 rand_num
用值 2
初始化。上述程式中有兩種方法 - rand
和 srand
。
rand
方法將一個新數字連線到初始化值。隨著種子上限的設定,rand
的 mod 和上限將返回一個低於上限的數字。
從此方法返回的最終結果被型別轉換為無符號整數。
srand()
方法將值從 rand_num
傳遞給種子變數 main_seed
。
使用上述方法的缺點
可以看出,執行 srand(time(0))
或為種子取任意值總是會在 rand()
上返回新的數字,這些數字取決於種子。但是在幾百萬之後,數字會重複。
種子控制按順序建立哪些隨機數,即 srand(1)
在第一次呼叫 rand()
時幾乎總是產生相同的值,第二次呼叫 rand()
時產生相同的數字,等等。
換句話說,如果在每次 rand()
呼叫之前重新播種相同的種子,則輸出始終是相同的隨機數。因此,在一秒鐘內使用 time(0)
播種幾次將導致重新播種後所有隨機數都相同。
它必須在幾個週期後重復,但 srand
引數定義了模式。C++ rand
不適合加密,因為知道種子有助於黑客估計下一個數字。
使用 C++ 生成類似於擲骰子的隨機值
該程式使用時間生成的種子來生成 1 到 6 範圍內的隨機數。
匯入包
本程式需要三個匯入包:
iostream
cstdlib
- 用於時間函式和 rand 操作time
- 時間函式的頭包
iostream
被匯入用於程式中的輸入輸出操作。另一個包 cstdlib
用於 C++ 程式中的基本控制操作。
第三個包是 time
包,將用於為程式建立種子。
根據 C++ 中的骰子生成值
一個骰子有 6 個單獨的值。該程式的作用必須是在該範圍內生成一個隨機自然數,該自然數可能會在隨後的擲骰中重複,但總體結果必須看起來完全隨機。
初始化三個變數以找到結果。變數 floor
和 ceiling
儲存骰子的最低和最高值,變數 outcome
用於查詢隨機數。
int outcome;
int l_limit = 1;
int h_limit = 6;
最終值是使用 rand()
函式生成的,將結果限制在上限和下限範圍內。
outcome = rand() % (max - min + 1) + min;
最後,返回變數 roll
。
int outcome;
int l_limit = 1; // floor or lower limit of a die
int h_limit = 6; // ceiling or higher limit of a die
outcome = rand() % (h_limit - l_limit + 1) + l_limit;
return outcome;
使用時間生成種子並顯示結果
程式在 srand()
函式中獲取當前時間並將其傳遞給 rand()
函式。應用程式使用 Droll()
方法中的 rand()
函式來查詢規定範圍內的自然數。
srand(time(0));
產生種子後,必須呼叫 Droll()
方法,並列印結果。
傳統上,三個模具輥總是被認為是一套完整的。該技術重複 3 次以驗證隨機性。
我們需要將 Droll()
方法放在 for
迴圈中,並在 print
語句中呼叫 3 次。最終結果是一個由擲骰子生成的 3X3 偽隨機數矩陣。
for (int i = 0; i < 3; i++) {
std::cout << Droll() << " ";
std::cout << Droll() << " ";
std::cout << Droll() << std::endl;
}
讓我們將所有內容放在程式中並檢視結果。
#include <cstdlib>
#include <iostream>
#include "time.h"
int Droll() {
int outcome;
int l_limit = 1; // floor or lower limit of a die
int h_limit = 6; // ceiling or higher limit of a die
outcome = rand() % (h_limit - l_limit + 1) + l_limit;
return outcome;
}
int main() {
srand(time(0));
for (int i = 0; i < 3; i++) {
std::cout << Droll() << " ";
std::cout << Droll() << " ";
std::cout << Droll() << std::endl;
}
}
輸出:
3 1 2
6 1 3
4 5 4
--------------------------------
Process exited after 0.00784 seconds with return value 0
Press any key to continue . . .
まとめ
本文解釋了偽數生成器的基礎知識。讀者已經看到了生成隨機數的不同方法及其優缺點。
給出了一個 C++ 程式,以使概念清楚地表明隨機數是如何在範圍內生成的,以及如何使用計算機程式來模擬擲骰子。