Setting up a Discrete Distribution in C++

10,216

Solution 1

From your linked page (emphasis mine)

std::piecewise_constant_distribution produces random floating-point numbers, which are uniformly distributed within each of the several subintervals [bi, bi+1), each with its own weight wi. The set of interval boundaries and the set of weights are the parameters of this distribution.

It expects floating point weights and boundaries, and one less weight than boundaries. It will also not output integers between 0-120, but floats.

You're passing it integer weights and boundaries so it fails to compile. But even when you fix that you're still going to get floating point values out of it...

Instead as you've discovered you want the disrete_distribution which you can set up like this: (modified from the linked pages documentation)

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

int main()
{
    // Setup the random bits
    std::random_device rd;
    std::mt19937 gen(rd());

    // Setup the weights (in this case linearly weighted)
    std::vector<int> weights;
    for(int i=0; i<120; ++i) {
        weights.push_back(i);
    }

    // Create the distribution with those weights
    std::discrete_distribution<> d(weights.begin(), weights.end());

    // use the distribution and print the results.
    std::map<int, int> m;
    for(int n=0; n<10000; ++n) {
        ++m[d(gen)/10];
    }
    for(auto p : m) {
        std::cout << p.first*10 << " - "<<p.first*10+9 << " generated " << p.second << " times\n";
    }
}

Solution 2

Try this piece of code and see if you get the same problem.

 // piecewise_constant_distribution
#include <iostream>
#include <array>
#include <random>

int main()
{
  const int nrolls = 10000; // number of experiments
  const int nstars = 100;   // maximum number of stars to distribute

  std::default_random_engine generator;
  std::array<double,6> intervals {0.0, 2.0, 4.0, 6.0, 8.0, 10.0};
  std::array<double,5> weights {2.0, 1.0, 2.0, 1.0, 2.0};
  std::piecewise_constant_distribution<double>
    distribution (intervals.begin(),intervals.end(),weights.begin());

  int p[10]={};

  for (int i=0; i<nrolls; ++i) {
    int number = distribution(generator);
    ++p[number];
  }

  std::cout << "a piecewise_constant_distribution:" << std::endl;
  for (int i=0; i<10; ++i) {
    std::cout << i << "-" << i+1 << ": ";
    std::cout << std::string(p[i]*nstars/nrolls,'*') << std::endl;
  }
  return 0;
}
Share:
10,216
Ryan J. Shrott
Author by

Ryan J. Shrott

Enjoy mathematics, computer science and hockey.

Updated on June 09, 2022

Comments

  • Ryan J. Shrott
    Ryan J. Shrott almost 2 years

    After hours of struggling with this issue, I cannot find any explanations for my error.

    I want the computer to pick a random number (weighted) between 0 and 120 (inclusive). I have an array, interval[], which holds the numbers from 0 to 120 (inclusive). I have another array, weights[], which holds the probabilities for choosing the ith element in the array. I want to define a probability distribution function for these data.

    Here is what I tried. I get an error saying that no instance of constructor matches the argument list.

    Snippet of my code:

    std::vector< int> weights(121);
    for (int i = 0; i < 121; i++)
    {
        weights[i] = (teamData[i]).S();
    }
    discrete_distribution<> dist(weights.begin(), weights.end());