线性同余法产生随机数C语言,使用线性同余法生成伪随机数/序列(C++实现)
最近朋友提出一個問題,自己編寫函數生成隨機數,一開始沒有認真思考,后來想了一下,如果是學習過計算機密碼學,應該很快就能設計出一些算法,這里使用了數論領域的相關知識——線性同余法簡單實現了生成隨機數算法。
以下是網上關于隨機數生成的一類說法:
在計算機上可以用物理方法來產生隨機數,但價格昂貴,不能重復,使用不便。另一種方法是用數學遞推公式產生,這樣產生的序列與真正的隨機數序列不同,所以稱為偽隨機數或偽隨機序列,只要方法和參數選擇合適,所產生的偽隨機數就能滿足均勻性和獨立性,與真正的隨機數具有相近的性質。
以下是一個使用了線性同余的遞推公式:
Xt = (X0 * 17 + 29) mod 500
線性同余中的線性,是指“線性”表示方程中 x 的次數是一次,mod 取余運算符則體現了“同余”這一數學概念。
式中,17 、29和500分別稱做乘數、增量和模數。使用線性同余生成隨機數的方法速度快,但對乘數、增量和模數的選取有一定的要求:
多次使用線性同余公式產生的序列應該看起來是隨機的,不循環的;
乘數/增量與模數互質;
這個函數能夠產生一個完整周期內的所有隨機數。這一要求由模數控制。
#include
#include
class MyRand
{
public:
unsigned int seed;
// 默認使用系統時間為種子
// time(NULL) 返回從1970年元旦午夜0點到現在的秒數
void srand(unsigned int s = (unsigned int)time(NULL))
{
seed = s;
}
// 使用了一種線性同余法,得到的隨機數最大為(2^15-1),29為質數中的一個
unsigned int rand()
{
seed = (seed * 31 + 13) % ((1 << 15) - 1);
return seed;
}
};
#include "rand.h"
int main()
{
MyRand a;
a.srand(); // 使用系統時間為種子
std::cout << "產生若干個隨機數:" << std::endl;
for (int i = 0; i < 100; i++)
std::cout << a.rand() % 100 << " "; // 生成0~100之間的隨機數
getchar();
return 0;
}
使用錯誤的公式,得到的序列并不隨機:
得到符合要求的偽隨機數序列:
在生成隨機數的過程中,會強調生成的是“偽”隨機數,這是因為平時編程中調用rand()函數(包括以上設計的函數)所產生的隨機數都是按照一定的公式模擬產生的,其結果是確定而可預見的。慶幸的是,若給rand()函數(包括以上自己設計的函數)提供不同的初始值(成為隨機種子seed),以真隨機數為運算的初始條件,就可以得到真正意義上的隨機數。
就牽扯到產生隨機種子的方法。產生種子的方法有很多,在程序設計的課程中介紹得最多的是使用系統時間time為種子。代碼中使用了time(NULL) 返回從1970年元旦午夜0點到現在的秒數作為隨機序列運算的初始值,每一次調用rand(),可得到不同的隨機序列。
事實上這種產生隨機種子的方法有一定的缺陷性。假設在一臺計算機上運行批量執行程序,程序執行的時間是幾個ms,那么幾個相鄰程序的seed是一樣的,每次調用隨機數生成函數的結果也是一樣的。這是因為系統時間time是按照秒級來計算的,而程序執行的時間是毫秒級,倘若在一秒內執行多次程序,必然導致產生的隨機種子相同。
總結
以上是生活随笔為你收集整理的线性同余法产生随机数C语言,使用线性同余法生成伪随机数/序列(C++实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab怎么计算地震波反应谱,基于M
- 下一篇: Scipy科学库