天天看點

C++ 實作随機數生成(Windows、Linux)

文章目錄

  • ​​1、簡介​​
  • ​​2、windows随機數​​
  • ​​2.1 随機數範圍計算公式​​
  • ​​2.2 rand()​​
  • ​​2.3 srand()​​
  • ​​2.4 c++11 <random>​​
  • ​​2.4.1 随機數生成引擎​​
  • ​​2.4.2 随機數分布律​​
  • ​​2.4.3 預定義算法​​
  • ​​2.4.4 random_device​​
  • ​​2.4.5 實作代碼​​
  • ​​3、linux随機數​​
  • ​​3.1 簡介​​
  • ​​3.2 指令​​
  • ​​3.2.1 /dev/random​​
  • ​​3.2.2 /proc/sys/kernel/random​​
  • ​​3.2.3 Haveged​​
  • ​​3.2.4 cpuinfo​​
  • ​​3.2.5 upower​​
  • ​​3.2.6 acpi​​
  • ​​3.2.7 ps​​
  • ​​3.2.8 kill​​
  • ​​3.2.9 /proc/version​​
  • ​​3.2.10 ip​​
  • ​​3.2.11 filezilla​​
  • ​​3.3 函數​​
  • ​​3.3.1 random​​
  • ​​3.3.2 ioctl​​
  • ​​3.3.3 /proc​​
  • ​​3.4 linux代碼示例​​
  • ​​3.4.1 gcc編譯​​
  • ​​3.4.2 g++編譯​​
  • ​​3.4.3 std::random_device​​
  • ​​結語​​

1、簡介

計算機的随機數都是由僞随機數,即是由小M多項式序列生成的,其中産生每個小序列都有一個初始值,即随機種子。(注意: 小M多項式序列的周期是65535,即每次利用一個随機種子生成的随機數的周期是65535,當你取得65535個随機數後它們又重複出現了。)
C++ 實作随機數生成(Windows、Linux)

僞随機數是用确定性的算法計算出來自[0,1]均勻分布的随機數序列。并不真正的随機,但具有類似于随機數的統計特征,如均勻性、獨立性等。在計算僞随機數時,若使用的初值(種子)不變,那麼僞随機數的數序也不變。

C++ 實作随機數生成(Windows、Linux)

僞随機數可以用計算機大量生成,在模拟研究中為了提高模拟效率,一般采用僞随機數代替真正的随機數。模拟中使用的一般是循環周期極長并能通過随機數檢驗的僞随機數,以保證計算結果的随機性。

C++ 實作随機數生成(Windows、Linux)

2、windows随機數

2.1 随機數範圍計算公式

産生一定範圍随機數的通用表示公式是:

要取得[0,n)  就是rand()%n     表示 從0到n-1的數
要取得[a,b)的随機整數,使用(rand() % (b-a))+ a; 
要取得[a,b]的随機整數,使用(rand() % (b-a+1))+ a; 
要取得(a,b]的随機整數,使用(rand() % (b-a))+ a + 1; 
通用公式:a + rand() % n;其中的a是起始值,n是整數的範圍。 
要取得a到b之間的随機整數,另一種表示:a + (int)b * rand() / (RAND_MAX + 1)。 
要取得0~1之間的浮點數,可以使用rand() / double(RAND_MAX)。      
C++ 實作随機數生成(Windows、Linux)
C++ 實作随機數生成(Windows、Linux)

2.2 rand()

rand()會傳回一随機數值, 範圍在0至RAND_MAX 間。RAND_MAX定義在stdlib.h, 其值為2147483647。

#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    for (int i = 0; i < 10000; i++)
    {
        cout << rand()%100<< " ";
    }
    return 0;
}      

2.3 srand()

srand()可用來設定rand()産生随機數時的随機數種子。通過設定不同的種子,我們可以擷取不同的随機數序列。可以利用srand((int)(time(NULL))的方法,利用系統時鐘,産生不同的随機數種子。不過要調用time(),需要加入頭檔案< ctime >。

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
    srand((int)time(0));  // 産生随機種子  把0換成NULL也可以
    for (int i = 0; i < 10000; i++)
    {
        cout << rand()%100<< " ";
    }
    return 0;
}      
#include <cstdlib>
#include <ctime>
using namespace std;
int main() 
{
    srand(time(nullptr)); // 用目前時間作為種子
    int min = 5, max = 10;
    int randomValue = (rand() % (max - min)) + min;//範圍[min,max)
    randomValue = (rand() % (max - min + 1)) + min;//範圍[min,max]
    randomValue = (rand() % (max - min)) + min + 1;//範圍(min,max]
}      

2.4 c++11

​​https://en.cppreference.com/w/cpp/numeric/random​​

C++标準建議使用代替rand()。

(since C++11)

中定義了随機數生成引擎、随機數分布律、不确定随機數和預定義的最佳算法實踐。

2.4.1 随機數生成引擎

提供了三種引擎,使用哪種需要權衡:

  • linear_congruential_engine(線性同餘随機數引擎):速度比較快,儲存很少的中間變量。
  • mersenne_twister_engine(梅森旋轉随機數引擎):比較慢,占用存儲空間較大,但是在參數設定合理的情況下,可生成最長的不重複序列,且具有良好的頻譜特征。
  • subtract_with_carry_engine(帶進位随機數引擎):速度最快,占用存儲空間較大,頻譜特性有時不佳。

上面的三種随機數生成算法均是模闆類,需要我們自己進行執行個體化;模闆類執行個體化需要的參數,均是算法中使用的參數,若是不懂其原理,建議不要使用這些模闆類。不過不用擔心,在C++11标準中,已經幫我們預先定義了一些随機數類(預定義算法),它們都是用過上面的三個類模闆執行個體化出來的。

2.4.2 随機數分布律

可以預先定義随機數分布的機率分布,如正态分布uniform_int_distribution、伯努利分布binomial_distribution、泊松分布poisson_distribution等等。

2.4.3 預定義算法

定義了算法的最佳實踐,避免了參數的選擇,可以直接選擇引擎,設定分布規律就好。算法包括minstd_rand0、minstd_rand、mt19937、mt19937_64、ranlux24_base、ranlux48_base等。

類名稱 屬性 依賴類
linear_congruential_engine templates \
mersenne_twister_engine templates \
subtract_with_carry_engine templates \
discard_block_engine Engine adaptors \
independent_bits_engine Engine adaptors \
shuffle_order_engine Engine adaptors \
default_random_engine instantiations 待定
minstd_rand instantiations linear_congruential_engine
minstd_rand0 instantiations linear_congruential_engine
mt19937 instantiations mersenne_twister_engine
mt19937_64 instantiations mersenne_twister_engine
ranlux24_base instantiations subtract_with_carry_engine
ranlux48_base instantiations subtract_with_carry_engine
ranlux24 instantiations ranlux24_base、discard_block_engine
ranlux48 instantiations ranlux48_base、discard_block_engine
knuth_b instantiations shuffle_order_engine

2.4.4 random_device

random_device是标準庫提供的一個非确定性随機數生成裝置,是所有生成器中唯一一個不需要随機數種子的方式。在Linux中,是需要讀取/dev/urandom裝置。需要注意的是random_device在某些作業系統中是無法使用的,會在構造函數或者調用operator()函數時抛出異常,是以在進行代碼移植時,需要格外注意。

2.4.5 實作代碼

#include <random>
using namespace std;

int main(){
  int min = 0,max = 100;
  random_device seed;//硬體生成随機數種子
  ranlux48 engine(seed());//利用種子生成随機數引擎
  uniform_int_distribution<> distrib(min, max);//設定随機數範圍,并為均勻分布
  int random = distrib(engine);//随機數
}      
#include <iostream>
#include <random>

int main(int argc, char**argv){
    std::default_random_engine engine;
    for (int i = 0; i < 10; ++i ){
        std::cout << engine() << " ";
    }
    std::cout << std::endl;
    return 0;
}      

3、linux随機數

3.1 簡介

/dev/random 和 /dev/urandom

/dev/urandom 是一個僞随機數生成器,缺乏熵它也不會停止。

/dev/random 是一個真随機數生成器,它會在缺乏熵的時候停止。

C++ 實作随機數生成(Windows、Linux)

3.2 指令

3.2.1 /dev/random

消耗完系統熵池中熵

cat /dev/random
cat /dev/random > /dev/null &      
C++ 實作随機數生成(Windows、Linux)

當熵池中熵值小于門檻值(cat /proc/sys/kernel/random/write_wakeup_threshold)時,系統會自動收集熵源資料,添加到熵池,增加熵值;當達到門檻值時,系統會停止收集熵源資料,熵池中熵值不會自動繼續增加。

3.2.2 /proc/sys/kernel/random

  • 檢視接口
ls      
C++ 實作随機數生成(Windows、Linux)
  • 檢視系統熵池中擁有的熵數

    This read-only file gives the available entropy, in bits. This will be a number in the range 0 to 4096。

cat      
C++ 實作随機數生成(Windows、Linux)
  • 檢視熵池容量

    說明熵池的大小(以位為機關)。This file is read-only, and gives the size of the entropy pool in bits. It contains the value 4096

cat      
  • 檢視從熵池中讀取熵的閥值

    當 entropy_avail 中的值少于這個閥值,這讀取 /dev/random 會被阻塞。

cat /proc/sys/kernel/random/read_wakeup_threshold
cat      
  • 産生随機字元串

    These read-only files contain random strings like 6fd5a44b-35f4-4ad4-a9b9-6b9be13e1fe9. The former is generated afresh for each read, the latter was generated once。

cat /proc/sys/kernel/random/uuid
cat      
C++ 實作随機數生成(Windows、Linux)

3.2.3 Haveged

Haveged 是一個守護程序,它使用處理器的“抖動”将熵添加到系統熵池中。

  • 安裝haveged:
# CentOS 7 yum install rng-tools haveged -y 
# Debian 9 apt install rng-tools haveged -y      
C++ 實作随機數生成(Windows、Linux)
  • 啟動haveged并開機啟動,并檢視haveged狀态:
systemctl start haveged                    #啟動
systemctl enable haveged                   #開機啟動
systemctl restart haveged                  #重新啟動
systemctl status haveged                   #檢視啟動狀态
systemctl list-unit-files | grep haveged    #檢視開機啟動狀态      
C++ 實作随機數生成(Windows、Linux)
C++ 實作随機數生成(Windows、Linux)
#rng-tools
systemctl enable rng-tools 
systemctl status rng-tools
#systemctl start rng-tools
service      
C++ 實作随機數生成(Windows、Linux)
sudo apt install pv
pv /dev/random >      
C++ 實作随機數生成(Windows、Linux)

使用 pv 我們可以看到我們通過管道傳遞了多少資料。正如你所看到的,在運作 haveged 之前,我們是 2.1 位/秒(B/s)。而在開始運作 haveged 之後,加入處理器的抖動到我們的熵池中,我們得到大約 1.5MiB/秒。

C++ 實作随機數生成(Windows、Linux)

3.2.4 cpuinfo

cat /proc/cpuinfo | grep      
C++ 實作随機數生成(Windows、Linux)

3.2.5 upower

upower 指令預裝在大多數的 Linux 發行版本中。為了使用 upower 指令來展示電池的狀态,打開終端并運作如下指令:

man upower
upower -e
upower -i /org/freedesktop/UPower/devices/battery_BAT0
upower -i `upower -e | grep 'BAT'`
upower -i $(upower -e | grep BAT) | grep --color=never -E "state|to\ full|to\ empty|percentage"      
C++ 實作随機數生成(Windows、Linux)
C++ 實作随機數生成(Windows、Linux)

3.2.6 acpi

acpi 指令可以用來顯示你的 Linux 發行版本中電池的狀态以及其他 ACPI 資訊。

在某些 Linux 發行版本中,你可能需要安裝 acpi 指令。

## Debian、 Ubuntu 及其衍生版本中安裝它
sudo apt-get install acpi
## RHEL、 CentOS、 Fedora 等系統中使用
sudo yum install acpi
sudo dnf install acpi
## 在 Arch Linux 及其衍生版本中使用
sudo      
man      
C++ 實作随機數生成(Windows、Linux)
C++ 實作随機數生成(Windows、Linux)
cat /sys/class/power_supply/BAT0/uevent 
cat /sys/class/power_supply/BAT0/capacity
find /sys/class/power_supply/BAT0/ -type f | xargs -tn1 cat      

3.2.7 ps

ps      
C++ 實作随機數生成(Windows、Linux)
## ps指令檢視所有程序
ps      
C++ 實作随機數生成(Windows、Linux)
## ps指令檢視具體某一應用的所有程序
## 檢視chrome 的所有程序
ps -aux|grep      
C++ 實作随機數生成(Windows、Linux)
## top指令目前時刻系統正在運作的所有程序
top      
C++ 實作随機數生成(Windows、Linux)

3.2.8 kill

kill      
C++ 實作随機數生成(Windows、Linux)
killall   (program應用名稱) 
pkill   (program應用名稱) 

## 針對奔潰的視窗程序,無法退出、關閉,無法通過kill程序來終止      

3.2.9 /proc/version

cat      
C++ 實作随機數生成(Windows、Linux)

3.2.10 ip

hostname      
C++ 實作随機數生成(Windows、Linux)
ip addr show | grep "inet"      
C++ 實作随機數生成(Windows、Linux)
/sbin/ifconfig | grep "inet addr"      

3.2.11 filezilla

sudo apt-get update
sudo apt-get install filezilla
sudo apt-get install filezilla-locales
sudo chmod -R 777      
C++ 實作随機數生成(Windows、Linux)
C++ 實作随機數生成(Windows、Linux)

3.3 函數

3.3.1 random

​​https://www.zx2c4.com/projects/linux-rng-5.17-5.18/​​​​https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git/tree/drivers/char/random.c​​

C++ 實作随機數生成(Windows、Linux)

3.3.2 ioctl

The following ioctl(2) requests are defined on file descriptors connected to either /dev/random or /dev/urandom. All requests performed will interact with the input entropy pool impacting both /dev/random and /dev/urandom. The CAP_SYS_ADMIN capability is required for all requests except RNDGETENTCNT.

The character special files /dev/random and /dev/urandom (present since Linux 1.3.30) provide an interface to the kernel’s random number generator. The file /dev/random has major device number 1 and minor device number 8. The file /dev/urandom has major device number 1 and minor device number 9.

#include <linux/random.h>
int ioctl(fd, RNDrequest, param);      
RNDGETENTCNT
          Retrieve the entropy count of the input pool, the contents
          will be the same as the entropy_avail file under proc.
          The result will be stored in the int pointed to by the
          argument.

   RNDADDTOENTCNT
          Increment or decrement the entropy count of the input pool
          by the value pointed to by the argument.

   RNDGETPOOL
          Removed in Linux 2.6.9.

   RNDADDENTROPY
          Add some additional entropy to the input pool,
          incrementing the entropy count.  This differs from writing
          to /dev/random or /dev/urandom, which only adds some data
          but does not increment the entropy count.  The following
          structure is used:

              struct rand_pool_info {
                  int    entropy_count;
                  int    buf_size;
                  __u32  buf[0];
              };

          Here entropy_count is the value added to (or subtracted
          from) the entropy count, and buf is the buffer of size
          buf_size which gets added to the entropy pool.

   RNDZAPENTCNT, RNDCLEARPOOL
          Zero the entropy count of all pools and add some system
          data (such as wall clock) to the pools.      

3.3.3 /proc

The files in the directory /proc/sys/kernel/random (present since 2.3.16) provide additional information about the /dev/random device:

entropy_avail
          This read-only file gives the available entropy, in bits.
          This will be a number in the range 0 to 4096.

   poolsize
          This file gives the size of the entropy pool.  The
          semantics of this file vary across kernel versions:

          Linux 2.4:
                 This file gives the size of the entropy pool in
                 bytes.  Normally, this file will have the value
                 512, but it is writable, and can be changed to any
                 value for which an algorithm is available.  The
                 choices are 32, 64, 128, 256, 512, 1024, or 2048.

          Linux 2.6 and later:
                 This file is read-only, and gives the size of the
                 entropy pool in bits.  It contains the value 4096.

   read_wakeup_threshold
          This file contains the number of bits of entropy required
          for waking up processes that sleep waiting for entropy
          from /dev/random.  The default is 64.

   write_wakeup_threshold
          This file contains the number of bits of entropy below
          which we wake up processes that do a select(2) or poll(2)
          for write access to /dev/random.  These values can be
          changed by writing to the files.

   uuid and boot_id
          These read-only files contain random strings like
          6fd5a44b-35f4-4ad4-a9b9-6b9be13e1fe9.  The former is
          generated afresh for each read, the latter was generated
          once.      

3.4 linux代碼示例

3.4.1 gcc編譯

那麼,到底如何分步編譯 C、C++ 程式呢?事實上,GCC 編譯器除了提供 gcc 和 g++ 這 2 個指令之外,還提供有大量的指令選項,友善使用者根據自己的需求自定義編譯方式。在前面的學習過程中,我們已經使用了一些指令選項,比如編譯 C++ 程式時 gcc 指令後跟的 -xc++、-lstdc++、-shared-libgcc,再比如手動指定可執行檔案名稱的 -o 選項。

注意,雖然我們僅編寫了一條 gcc 或者 g++ 指令,但其底層依據是按照預處理、編譯、彙編、連結的過程将 C 、C++ 程式轉變為可執行程式的。而本應在預處理階段、編譯階段、彙編階段生成的中間檔案,此執行方式預設是不會生成的,隻會生成最終的 a.out 可執行檔案(除非為 gcc 或者 g++ 額外添加 -save-temps 選項)。

gcc/g++指令選項 功 能
-E(大寫) 預處理指定的源檔案,不進行編譯。
-S(大寫) 編譯指定的源檔案,但是不進行彙編。
-c 編譯、彙編指定的源檔案,但是不進行連結。
-o 指定生成檔案的檔案名。
-llibrary(-I library) 其中 library 表示要搜尋的庫檔案的名稱。該選項用于手動指定連結環節中程式可以調用的庫檔案。建議 -l 和庫檔案名之間不使用空格,比如 -lstdc++。
-ansi 對于 C 語言程式來說,其等價于 -std=c90;對于 C++ 程式來說,其等價于 -std=c++98。
-std= 手動指令程式設計語言所遵循的标準,例如 c89、c90、c++98、c++11 等。

當然,gcc 指令也為使用者提供了“手動指定代表編譯方式”的接口,即使用 -x 選項。例如,gcc -xc xxx 表示以編譯 C 語言代碼的方式編譯 xxx 檔案;而 gcc -xc++ xxx 則表示以編譯 C++ 代碼的方式編譯 xxx 檔案。

## 如果想使用 gcc 指令來編譯執行 C++ 程式,需要在使用 gcc 指令時,手動為其添加 -lstdc++ -shared-libgcc 選項,表示 gcc 在編譯 C++ 程式時可以連結必要的 C++ 标準庫。
## gcc -xc++ demo.cpp -lstdc++ -shared-libgcc
g++ demo.cpp  #或者 gcc -xc++ -lstdc++ -shared-libgcc demo.cpp
./a.out

## 将 main.c 和 func.c 兩個源檔案編譯成一個可執行檔案,其名字為 app.out。
## 如果不使用 -o 選項,那麼将生成名字為 a.out 的可執行檔案。
gcc main.c func.c -o app.out

## GCC一次編譯多檔案項目
gcc myfun.c main.c -o main.exe
./main.exe
#or
gcc -c myfun.c main.c
gcc myfun.o main.o -o main.exe
./main.exe
#or
gcc *.c -o main.exe
./main.exe

## GCC 編譯器無法找到 cos() 這個函數。為了編譯這個 main.c,必須使用-l選項,以連結數學庫:
## 數學庫的檔案名是 libm.a。字首lib和字尾.a是标準的,m是基本名稱,GCC 會在-l選項後緊跟着的基本名稱的基礎上自動添加這些字首、字尾,本例中,基本名稱為 m。
## 在支援動态連結的系統上,GCC 自動使用在 Darwin 上的共享連結庫 libm.so 或 libm.dylib。
gcc main.c -o main.out -lm

## (1)把連結庫作為一般的目标檔案,為 GCC 指定該連結庫的完整路徑與檔案名。
## 如果連結庫名為 libm.a,并且位于 /usr/lib 目錄,那麼下面的指令會讓 GCC 編譯 main.c,然後将 libm.a 連結到 main.o:
gcc main.c -o main.out /usr/lib/libm.a

## (2)使用-L選項,為 GCC 增加另一個搜尋連結庫的目錄:
## 可以使用多個-L選項,或者在一個-L選項内使用冒号分割的路徑清單。
gcc main.c -o main.out -L/usr/lib -lm

## (3)把包括所需連結庫的目錄加到環境變量 LIBRARYPATH 中。      
  • -Wall選項

    使gcc産生盡可能多的警告資訊,警告資訊很有可能是錯誤的來源,特别是隐式程式設計錯誤,是以盡量保持0 warning。

  • -Werror 選項

    要求gcc将所有的警告當作錯誤進行處理。

  • -fPIC選項

    PIC指Position Independent Code。共享庫要求有此選項,以便實作動态連接配接(dynamic linking)。

  • -I 選項(大寫的 i)

    向頭檔案搜尋目錄中添加新的目錄。

    1、用#include"file"的時候,gcc/g++會先在目前目錄查找你所制定的頭檔案,如

    果沒有找到,他回到預設的頭檔案目錄找。

    如果使用-I制定了目錄,他會先在你所制定的目錄查找,然後再按正常的順序去找.

    2、用#include,gcc/g++會到-I制定的目錄查找,查找不到,然後将到系統的缺

    省的頭檔案目錄查找

    例如:gcc –I /usr/dev/mysql/include test.c –o test.o

  • -l選項(小寫的 l)

    說明庫檔案的名字。如果庫檔案為 libtest.so, 則選項為: -ltest

  • -L選項

    說明庫檔案所在的路徑。

    例如:-L.(“.”表示目前路徑)。 -L/usr/lib (“/usr/lib” 為路徑。注:這裡的路徑是絕對路徑)

    如果沒有提供 -L選項,gcc 将在預設庫檔案路徑下搜尋

  • -shared選項指定生成動态連接配接庫,不用該标志外部程式無法連接配接。相當于一個可執行檔案, 生成 .so 檔案
  • -static 選項,強制使用靜态連結庫,生成 .a 檔案。因為gcc在連結時優先選擇動态連結庫,隻有當動态連結庫不存在時才使用靜态連結庫。加上該選項可強制使用靜态連結庫。

    .so 和 .a 的差別:運作時動态加載,編譯時靜态加載

3.4.2 g++編譯

g++ filename.cpp
g++ filename.cpp -o filename

g++ -c 1.cpp -o 1.o
g++ -c 2.cpp -o 2.o
g++ 1.o 2.o -o out

g++ -o filename filename.cpp
g++ -o filename file1.cpp file2.cpp

g++ hello.cpp -fPIC -shared -o libworld.so
g++ hello.cpp -o world      

3.4.3 std::random_device

真随機數利用某些自然因素(如熵)的随機性生成。Linux 中的 /dev/random 生成的就是真随機數。

僞随機數則利用一些生成算法來産生。通常來講,C++ 中生成的随機數就是僞随機數。

  • (1)LCG

    rand() 利用的是線性同餘法(LCG)生成僞随機數。LCG 的優勢在于速度快、占用記憶體小。但是由于其不夠随機,是以并不能把它用在蒙特卡洛之類的算法上。

  • (2)RANLUX

    ranlux 本質上還是 LCG,不過它使用的是帶進位減法(Subtract-With-Carry)。顯然,等級越高,随機數越難以被預測。綜合考慮性能等因素,3 級在現實中使用較多。

  • (3)梅森旋轉(Mersenne Twister - C++ 中的 mt1993)也是一種僞随機數生成方法,不過可以生成比 LCG 品質高得多的随機數。MT 得名于其周期為梅森素數。其利用的是 LFSR(更準确地講,是 GFSR)。
  • (4)C++ 中也提供了真随機數 random_device。它在 Windows 下調用 rand_s,在 Linux 下調用 /dev/urandom。真随機數的優點是足夠随機,但它會消耗很多系統資源,在某些情況下是不可接受的。在真随機數的生成裡,把随機數的生成分成兩個部分,第一個部分稱之為熵生成,指的就是前面說的各類噪聲,第二部分就是熵提取,指的就是把噪聲資料進行變化。

真随機數發生器(TRNG):是指利用實體方法實作的随機數發生器。它是自然界随機的實體過程(所産實體現象的不确定性)的反映,即使算法等TRNG的所有資訊都被暴露,都無法猜測其結果,即高品質的真随機數發生器産生的随機數永遠不具備周期性。這就使其在本質上差別于廣泛應用的僞随機數發生器(PRNG),僞随機數發生器是基于數學算法的随機數發生器,它由真随機的種子和僞随機網絡構成。

僞随機數生成器(PRNG):是由馮諾依曼在 1946 年創造的。他的基本思想是從一個随機數種子開始,對其平方,然後取中間值。接下來重複對得到的數取平方并取中間值的過程,就會得到一個具有統計意義屬性的随機數序列了。這也就是廣為人知的平方取中法。然而,馮諾依曼的方法并沒有經得住時間的考驗,因為不論從什麼随機種子開始,序列最終都會落入某個短循環序列,比如:8100,6100,4100,8100,6100,4100……。1949 年,數學家 D.H.Lehmer 利用線性同餘生成器(LCG)實作了這一思路。下面給出的是基于 Lehmer 的方法所實作的一種樸素 PRNG,叫做中央随機數生成器,使用 JavaScript 在 1995 年寫的。

#include <iostream>
#include <random>
double getRandomDevice()
{
  std::random_device rd;
  std::mt19937 mt(rd());
  return (unsigned int)mt();
}      

結語

繼續閱讀