在C ++中生成具有给定概率的随机数

时间:2018-05-10 12:06:28

标签: c++ random

当获得0的概率为10%,1为7%且获得其余数字的概率相等时,如何使用rand()函数在C ++中生成0到100之间的随机数? / p>

2 个答案:

答案 0 :(得分:3)

rand()功能可能是在这里完成工作的错误工具。 C ++,因为C ++ 11有(伪)随机数生成的新工具:http://en.cppreference.com/w/cpp/numeric/random这些工具中有RandomNumberDistribution的概念,其中一个分发由std::discrete_distribution提供。 std :: discrete_distribution允许您定义分布中数字的权重,以便不同的数字可以具有不同的预定义概率。

#include <iostream>
#include <map>
#include <random>
#include <cmath>

int main()
{
    std::random_device r;
    std::default_random_engine e1(r());
    // Distribution that defines different weights (17, 10, etc.) for numbers.
    std::discrete_distribution<int> discrete_dist({17, 10, 5, 3, 1});

    // The map keeps track of number of occurences for each value.
    std::map<int, int> histogram;
    for (int n = 0; n < 100; ++n) {
        ++histogram[std::round(discrete_dist(e1))];
    }
    std::cout << "Distribution:\n";
    for (auto p : histogram) {
        std::cout << p.first << ' ' << p.second << '\n';
    }
}

输出可能类似于:

Distribution:
0 51
1 23
2 13
3 9
4 4

答案 1 :(得分:0)

您可以使用std :: uniform_real_distribution以及间隔表来执行此类查找。

我们可以做的是生成一个从0.0到1.0的数字,并使用一种查找表将其映射到整数空间。

例如:

#include <random>
#include <vector>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <map>

struct TableEntry
{
    double upper_bound = 0.0f;
    int value = 0;

    //for std::is_sorted, std::Upper_bound;
    bool operator<(TableEntry const& other) const
    {
        return this->upper_bound < other.upper_bound;
    }

};

struct Generator
{
    Generator():
        gen(std::random_device()()), //seed the random number generator
        dis(0.0, 1.0) //we want a value between - and 1
    {
        break_table.push_back({0.1, 0}); //10 percent probability of yielding 0
        break_table.push_back({0.17, 1}); // (0.17 - 0.1) == 7% chance of yielding 1

        //fill in the rest of the table uniformly

        double step = (1.0 - 0.17)/98; //98 values remaining, distribute equally

        for(int i = 2; i < 100; i++)
        {
            break_table.push_back({0.17 + (i-1)*step, i});
        }

        assert(std::is_sorted(begin(break_table), end(break_table)));
        assert(abs(break_table.back().upper_bound - 1.0) < 0.00001);
    }

    //call the object as a function to get a value
    int operator()()
    {
        double bval = dis(gen); //bval is in interval [0, 1);

        // std::upper_bound returns an iterator to the first value bigger than bval
        auto break_entry = std::upper_bound(begin(break_table), end(break_table), TableEntry{bval, 0});

        //special case: we're off the end of the scale
        if(break_entry == end(break_table)) return break_table.back().value;
        else return break_entry->value;
    };

private:

    std::vector<TableEntry> break_table;
    std::mt19937 gen;
    std::uniform_real_distribution<double> dis;
};




int main()
{
    Generator g;

    //verify the probabilities
    const size_t N = 10'000'000;
    std::map<int, size_t> number_counts; // keep track of occurences of each number
    for(size_t i = 0; i < N; i++)
    {
        int v = g();
        number_counts[v]++;
    }
    for(auto const& kv: number_counts)
    {
        double p = static_cast<double>(kv.second) / N;
        std::cout << kv.first << " : " << p * 100.0 << "%\n";
    }
    return 0;
}

运行此代码后,我得到以下分布:

0 : 10.0069%
1 : 7.01544%
2 : 0.84899%
3 : 0.84358%
4 : 0.8462%
5 : 0.84468%
6 : 0.85324%
7 : 0.85023%
8 : 0.85003%
9 : 0.84862%
...
99 : 0.84219%

......看起来很不错。