C++生成隨機數

C++爲隨機數提供了兩套工具:C風格的和C++風格的。ios

C風格

C爲隨機數提供的工具是randsrandRAND_MAX,定義在<stdlib.h>中。dom

srandrand設置種子,若是不設置,至關於調用過srand(1)rand產生僞隨機數,其範圍爲0RAND_MAXRAND_MAX至少是32767,在MSVC和GCC中這個值都是32767函數

僞隨機數看似隨機,實則是有規律可循的,對於相同的種子值,rand產生的序列徹底相同,也就是說不管你給srand一個什麼數字,屢次運行程序的結果都將相同——除非你給srand的是不一樣的數字,好比時間。<time.h>中的time函數返回整數表示的系統時間,可用於設置種子。工具

若是咱們只須要09的隨機數,能夠把rand的返回值% 10;若是是42233,能夠寫rand() % 192 + 42。下面的random函數封裝了這項工做。注意只有在b - a + 1遠小於或整除RAND_MAX時隨機數的分佈才比較均勻。性能

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int random(int a, int b)
{
    return rand() % (b - a + 1) + a;
}

int main()
{
    srand(time(NULL));
    printf("RAND_MAX = %d\n", RAND_MAX);
    for (int i = 0; i < 10; i++)
        printf("%d ", rand());
    printf("\n");
    int count[10] = {0};
    for (int i = 0; i < 10000; i++)
        count[random(0, 9)]++;
    for (int i = 0; i < 10; i++)
    {
        printf("%d: ", i);
        for (int j = 0; j < count[i] / 10; j++)
            printf("*");
        printf("\n");
    }
}

C++風格

從C++11開始,C++標準規定了隨機數設施,包括均勻隨機位生成器(Uniform random bit generators,URBG)和隨機數分佈等,定義在<random>中。code

URBG分爲隨機數引擎、引擎適配器、預置隨機數生成器和非肯定隨機數生成器4類,一般後兩類就夠用了。orm

標準規定了3種隨機數引擎:內存

  • 線性同餘linear_congruential_engine(LCG),時間空間消耗都少;開發

  • 梅森旋轉mersenne_twister_engine(MT),佔用較多內存(在PC上能夠忽略),計算量較大;rem

  • 帶進位減法(屬於滯後斐波那契生成器,LFG)subtract_with_carry_engine,性能與效果折中。

隨機數引擎都須要一個種子,生成的都是僞隨機數。

引擎適配器能夠套一個隨機數引擎:

  • discard_block_engine在連續若干個僞隨機數中選擇若干個;

  • independent_bits_engine把位數多的僞隨機數壓縮成位數少的;

  • shuffle_order_engine把連續若干個僞隨機數重排。

套娃的方式是模板,理論上你還能夠用適配器套適配器,不過CPU可能會有意見。

隨機數引擎的模板參數怎麼取?標準定義了一些數學家們發現的效果良好的隨機數引擎:LCG minstd_rand0minstd_randknuth_b;MT mt19937mt19937_64;LFG ranlux24_baseranlux48_baseranlux24ranlux48。若是你仍是無從下手,那就用default_random_engine,編譯器的開發者們爲你選好了他們認爲最合適的,在MSVC中是mt19937,在GCC中是minstd_rand0

以上工具都生成僞隨機數,標準還定義了真·隨機數引擎random_device,儘管標準也容許它是僞隨機的。若是它是真隨機的,那麼使用起來它的效果無疑是最好的,可是屢次調用後性能會急劇降低,一般只用於生成僞隨機數引擎的種子。

隨機數生成器類型都定義了靜態方法minmax,返回生成的隨機數的範圍,以及無參數的函數調用運算符operator(),返回隨機數。

#include <iostream>
#include <random>

int main()
{
    auto engine = std::default_random_engine(std::random_device()());
    std::cout << "min = " << engine.min() << "; max = " << engine.max() << std::endl;
    std::cout << "random numbers: ";
    for (int i = 0; i != 10; ++i)
        std::cout << engine() << ' ';
    std::cout << std::endl;
}

大多數狀況下咱們不須要minmax範圍的整數,而須要必定分佈的整數或實數。標準規定了許多隨機數分佈類型,我數學很差,不太懂這些。

  • 均勻分佈uniform_int_distributionuniform_real_distribution

  • 伯努利分佈bernoulli_distributionbinomial_distributionnegative_binomial_distributiongeometric_distribution

  • 泊松分佈poisson_distributionexponential_distributiongamma_distributionweibull_distributionextreme_value_distribution

  • 正態分佈normal_distributionlognormal_distributionchi_squared_distributioncauchy_distributionfisher_f_distributionstudent_t_distribution

  • 抽樣分佈discrete_distributionpiecewise_constant_distributionpiecewise_linear_distribution

構造分佈實例時傳入分佈的參數。調用operator()得到結果,參數爲隨機數引擎。

#include <iostream>
#include <random>
#include <string>

int main()
{
    auto engine = std::default_random_engine(std::random_device()());
    std::uniform_int_distribution<int> uniform(0, 9);
    int count[10] = {0};
    for (int i = 0; i != 10000; ++i)
        ++count[uniform(engine)];
    for (int i = 0; i != 10; ++i)
        std::cout << i << ": " << std::string(count[i] / 10, '*') << std::endl;
}

注意,與STL中左閉右開的習慣不一樣,uniform_int_distribution構造函數接受的參數是閉區間。

相關文章
相關標籤/搜索