簡體   English   中英

我可以在現代 C++ 中排除隨機數范圍內的數字或子范圍嗎?

[英]Can i exclude a number or subrange of numbers inside a range of random numbers in modern C++?

我有:

std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> probability(0, 100);

我想排除這個概率范圍內的一些數字。
示例 1:假設我想生成一個 0 到 100 之間的隨機數,但這個數字永遠不能是 4。
示例 2:假設我想生成一個 0 到 100 之間的隨機數,但這個數永遠不能是 4 到 7 之間的任何數字。

我想知道是否可以在不使用 std::rand 的情況下在現代 C++ 中實現?
提前致謝!

如果你想繼續使用uniform_int_distribution你可以像這樣手動完成:

示例 1:假設我想生成一個 0 到 100 之間的隨機數,但這個數字永遠不能是 4。

std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> distribution(0,99);
auto temp = distribution(mt);
auto random_number = (temp < 4) ? temp : temp + 1;

示例 2:假設我想生成一個 0 到 100 之間的隨機數,但這個數永遠不能是 4 到 7 之間的任何數字。

std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> distribution(0,96);
auto temp = distribution(mt);
auto random_number = (temp < 4) ? temp : temp + 4;

這可以概括為編寫一個函數random_int_between_excluding(int first, int last, std::vector<int> exclude) ,盡管在某些時候遵循 NathanOlivers 的建議並使用std::discrete_distribution會更簡單。

示例 2:假設我想生成一個 0 到 100 之間的隨機數,但這個數永遠不能是 4 到 7 之間的任何數字。

這就是std::piecewise_constant_distribution的用途。

    std::vector<int> i{0,  4, 8, 101};
    std::vector<int> w{ 4,  0,  93};
    std::piecewise_constant_distribution<> d(i.begin(), i.end(), w.begin());

現場演示

如果你想錯過 4,那么一個很好的方法(它不會損害生成器的任何統計特性),是在半開區間 [0, 99) 中繪制,如果數字是 4,則加 1或更大。

您可以執行類似於省略范圍內的數字的操作。

這種方法是對與所需概率分布相關聯的分位數函數進行建模的一種令人驚訝的好方法。

您可以在均勻分布上使用任意復雜度的過濾器:

template<typename D, typename G, typename F>
auto sample(D &distribution, G &generator, F const &filter)
{
    while(true)
    {
        auto const value = distribution(generator);
        if(filter(value))
            return value;
    }
}

您的示例案例轉換為以下內容

std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> probability(0, 100);

auto const filter = +[](int n) {return n < 4 || n > 7;}
int const i = sample(probability, mt, filter);

您必須記住,這種過濾是有代價的。

N為分布返回的不同值的數量, F - 過濾掉的這些值的數量; 然后,如果您需要對S值進行采樣,則必須對S * N / (N - F)值進行平均采樣和過濾。 如果 F 與 N 相比較小,那沒關系,但是當 F 接近 N 時效率非常低。在您的情況下, N = 100F = 4N / (N - F) = 1.04166...

如果您更喜歡可讀性和簡單性,那是您的選擇。 否則,如果您需要性能,最好嘗試分段分布或手動調整值范圍。

有一個選項可以在合理的數字范圍內手動執行...,創建一個查找表並排除無效的數字:

 static int rand_pool[]{1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}; //no number 4
    srand((int)time(0));
        int random_number = rand_pool[rand() % 22];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM