AdminBenni AdminBenni - 2 months ago 9
C++ Question

Random ints with different likelihoods

I was wondering if there was a way to have a random number between A an b and where if a number meets a certain requirement it is more likely to appear than all the other numbers between A and B, for example: Lower numbers are more likely to appear so if A = 1 and B = 10 then 1 would be the likeliest and 10 would be the unlikeliest.

All help is appreciated :) (sorry for bad English/grammar/question)

Answer

C++11 (which you should absolutely be using by now) added the <random> header to the C++ standard library. This header provides much higher quality random number generators to C++. Using srand() and rand() has never been a very good idea because there's no guarantee of quality, but now it's truly inexcusable.

In your example, it sounds like you want what would probably be called a 'discrete triangular distribution': the probability mass function looks like a triangle. The easiest (but perhaps not the most efficient) way to implement this in C++ would be the discrete distribution included in <random>:

auto discrete_triangular_distribution(int max) {
    std::vector<int> weights(max);
    std::iota(weights.begin(), weights.end(), 0);
    std::discrete_distribution<> dist(weights.begin(), weights.end());
    return dist;
}

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());
    auto&& dist = discrete_triangular_distribution(10);
    std::map<int, int> counts;
    for (int i = 0; i < 10000; i++)
        ++counts[dist(gen)];
    for (auto count: counts)
        std::cout << count.first << " generated ";
        std::cout << count.second << " times.\n";
}

which for me gives the following output:

1 generated 233 times.
2 generated 425 times.
3 generated 677 times.
4 generated 854 times.
5 generated 1130 times.
6 generated 1334 times.
7 generated 1565 times.
8 generated 1804 times.
9 generated 1978 times.

Things more complex than this would be better served with either using one of the existing distributions (I have been told that all commonly used statistical distributions are included) or by writing your own distribution, which isn't too hard: it just has to be an object with a function call operator that takes a random bit generator and uses those bits to produce (in this case) random numbers. But you could create one that made random strings, or any arbitrary random objects, perhaps for testing purposes).

Comments