If your weights change more slowly than they are drawn, C ++ 11 discrete_distribution will be the easiest:
#include <random> #include <vector> std::vector<double> weights{90,56,4}; std::discrete_distribution<int> dist(std::begin(weights), std::end(weights)); std::mt19937 gen; gen.seed(time(0));//if you want different results from different runs int N = 100000; std::vector<int> samples(N); for(auto & i: samples) i = dist(gen); //do something with your samples...
Note, however, that C ++ 11 discrete_distribution calculates all the cumulative amounts during initialization. This is usually necessary because it speeds up the sampling time for a one-time cost of O (N). But for a rapidly changing distribution, it will carry heavy costing (and memory). For example, if the weights represented the number of elements that are, and each time you draw one, you delete it, you probably want to create your own algorithm.
Will answer overflow https://stackoverflow.com/a/2129609/29023/ ... , avoiding these overheads, but will be slower to draw than C ++ 11 because it cannot use binary search.
To see that it does this, you can see the corresponding lines ( /usr/include/c++/5/bits/random.tcc in my Ubuntu 16.04 + GCC 5.3 installation):
template<typename _IntType> void discrete_distribution<_IntType>::param_type:: _M_initialize() { if (_M_prob.size() < 2) { _M_prob.clear(); return; } const double __sum = std::accumulate(_M_prob.begin(), _M_prob.end(), 0.0); // Now normalize the probabilites. __detail::__normalize(_M_prob.begin(), _M_prob.end(), _M_prob.begin(), __sum); // Accumulate partial sums. _M_cp.reserve(_M_prob.size()); std::partial_sum(_M_prob.begin(), _M_prob.end(), std::back_inserter(_M_cp)); // Make sure the last cumulative probability is one. _M_cp[_M_cp.size() - 1] = 1.0; }
mmdanziger Jul 6 '16 at 7:33 2016-07-06 07:33
source share