How to generate random numbers with a probability

closed account (EAp4z8AR)
I have to generate a dice roll with a probability and the probability is determined by the user entering the weight of each side. How would I generate random numbers with probability.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
void input()
{
    int side;
    cout << "Enter the sides for a die (2 or greater).\n";
    cin >> side ;
    while (side < 2)
    {
        cout << "Enter the sides for a die (2 or greater).\n";
        cin >> side;
    }
    
    double weight[side-1];
    double *p;
    p = weight;
    for (int i=0; i<=(side-1); i++)
    {
        cout << "Enter the weights for each side (greater than 0).\n";
        cin >> *p;
        
        if (*p > 0)
        {
            weight[i] = *p;
        }
        
        while (*p <= 0)
        {
            cout << "Invalid weight entered. Try again.\n";
            cout << "Enter the weights for each side (greater than 0).\n";
            cin >> *p;
        }
    }
    roll(side, p);
    menu();
}


int roll(int sides, double *weights)
{
    int roll, output;
    cout << "Please enter the amounts of times you want to roll the dice (greater than 0).\n";
    cin >> roll;
    
    srand(time(0));
    
    if (roll>=1 && roll<=sides)
    {
        output = (rand() % sides) + 1;
    }
    
    
    while (roll<1 || roll>sides)
    {
        cout << "Error. Please try again.";
        cout << "Please enter the amounts of times you want to roll the dice (greater than 0).\n";
        cin >> roll;
    }
}
> How would I generate random numbers with probability.

Use std::discrete_distribution https://en.cppreference.com/w/cpp/numeric/random/discrete_distribution

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <string>
#include <vector>
#include <random>

template < typename T >
T get_number( const std::string& prompt, T minv, T maxv )
{
    std::cout << prompt << " [" << minv << ',' << maxv << "]: " ;
    T value ;
    if( std::cin >> value && value >= minv && value <= maxv ) return value ;

    std::cin.clear() ; // clear a possible failed state (user did not enter a number)
    std::cin.ignore( 1000, '\n' ) ; // throw the offending input away
    std::cout << "invalid input. try again\n" ;
    return get_number( prompt, minv, maxv ) ; // and try again
}

void roll( const std::vector<double>& weights, int nrolls )
{
    // https://en.cppreference.com/w/cpp/numeric/random
    static std::mt19937 rng( std::random_device{}() ) ;

    // https://en.cppreference.com/w/cpp/numeric/random/discrete_distribution/discrete_distribution
    std::discrete_distribution<int> distrib( weights.begin(), weights.end() ) ;

    for( int r = 0 ; r < nrolls ; ++r )
        std::cout << "roll #" << r+1 << ": " << distrib(rng) + 1 << '\n' ;
}

int main()
{
    const int nsides = get_number( "enter number of sides of the die", 2, 100 ) ;

    // https://cal-linux.com/tutorials/vectors.html
    std::vector<double> weights(nsides) ;
    for( int i = 0 ; i < nsides ; ++i )
        weights[i] = get_number( "weight for side #" + std::to_string(i+1), 0.0, 10.0 ) ;

    const int nrolls = get_number( "number of rolls", 2, nsides ) ;
    roll( weights, nrolls ) ;
}

Version with rand().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <cmath>
using namespace std;


//======================================================================


// Return the upper limits of each partition of random numbers
vector<int> weightToLimit( const vector<double> &weight )
{
   int N = weight.size();

   // Find cumulative weights
   vector<double> sumWeight( N );
   for ( int i = 0; i < N; i++ ) sumWeight[i] = ( i ? sumWeight[i-1] : 0 ) + weight[i];

   // Split a CONTINUOUS number range -0.5 to RAND_MAX + 0.5, then round DOWN to get upper limits (inc. -1)
   vector<int> upperLimit( N );
   for ( int i = 0; i < N; i++ ) upperLimit[i] = floor( -0.5 + ( 1.0 + RAND_MAX ) * sumWeight[i] / sumWeight[N-1] );

   return upperLimit;
}


//======================================================================


// Return the result of one roll (between 0 and SIDES - 1)
int roll( const vector<int> &upperLimit )
{
   int r = rand();
   int i = 0;
   while ( upperLimit[i] < r ) i++;
   return i;
}


//======================================================================


int main()
{
   srand( time( 0 ) );

// vector<double> weight = { 1, 1, 1, 1, 1, 1 };           // Unbiased 6-sided die
   vector<double> weight = { 0, 0, 1, 1, 2, 2 };           // Very biased die

   int SIDES = weight.size();
   int NROLLS = 1000000;

   vector<int> number( SIDES, 0 );
   vector<int> upperLimit = weightToLimit( weight );
   for ( int r = 1; r <= NROLLS; r++ ) number[ roll( upperLimit ) ]++;

   cout << "Percentages:\n";
   for ( int s = 1; s <= SIDES; s++ )
   {
      cout << s << '\t' << 100.0 * number[s-1] / NROLLS << '\n';
   }
}


Unbiased die:
Percentages:
1	16.6481
2	16.6627
3	16.6486
4	16.6653
5	16.7071
6	16.6682


Very biased die:
Percentages:
1	0
2	0
3	16.684
4	16.7675
5	33.2184
6	33.3301
Topic archived. No new replies allowed.