3

I am not quite sure how to go about this.

I need to generate 14,296 random numbers with different levels of probability.

so for example I need an array containing the numbers 18, 1, and 17. Each number has a different percent probability of occuring. So:

55% = 18
(7,862.8 times)

30% = 1
(4,288.8 times)

15% = 17
(2,144.4 times)

the result would be something like new Array () { 18, 18, 1, 17, 1, 18...}

Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
Tom Fobear
  • 6,729
  • 7
  • 42
  • 74
  • To clarify, the input is 1) a set of numbers each with an associated desired probability, and 2) a desired output array size? – JYelton Aug 10 '11 at 19:36
  • the input is right the output is an array of size N with N / a.probabilty elements with the value of a – Tom Fobear Aug 10 '11 at 19:46
  • So many good answers, I acctually don't know which one to pick this time! – Tom Fobear Aug 10 '11 at 19:47
  • Do you need true randomness, or "predictable randomness"? Using your example for true randomness, you could end up with 1% 18, 95% 17, 4% 1. Not sure if those types of results would be acceptable for you. – Odnxe Aug 10 '11 at 19:56
  • @Odnxe what do you mean? – Tom Fobear Aug 10 '11 at 20:36
  • 1
    @Tom Fobear There is a very through discussion about here http://stackoverflow.com/questions/910215/need-for-predictable-random-generator using a shuffle bag http://kaioa.com/node/53 solves the problem a random generator being to random. – Odnxe Aug 10 '11 at 20:58

5 Answers5

4

If you'll always have the values as integer percentages, I'd fill a 100-element array with values according to the probability, so in this case your array would have 55 occurrences of 18, 30 occurrences of 1, and 15 occurrences of 17. Then you just need to pick 14,296 random values from that array. (i.e. pick an integer in the range [0, 100) and take that element.)

For different ways of expressing the probabilities, there are different approaches, of course. But if you're given integer percentages, this is an easily-understood option. (Another way is to scale all of the probabilities by the total, i.e. into a range of [0, 1), and then take a random double in that range.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

Divide the range of random generator into proportional segments, and, judging to which segment the next random number has fallen into, select the corresponding number from your set.

Something like (simplified):

const int numbers[3] = { 1, 17, 18 };
const int borders[2] = { 0.30*MAX_RANDOM, (0.30 + 0.15) *  MAX_RANDOM };

int i = random.next(), num;

if      (i < borders[0]) num = number[0];
else if (i < borders[0]) num = number[1];
else num = number[2];

Of course, if there's more numbers than three, it's better to use a loop.

Note: unlike Jon Skeet's solution, this one can provide any desired granularity up to 1/(MAX_RANDOM+1) (which is often up to 2^32 on 32-bit machines), rather than strictly 1%.

vines
  • 5,160
  • 1
  • 27
  • 49
1
Random r = new Random();

// for each number to generate
int nextNumber;
double probability = r.NextDouble();
if (probability < 55.0 / 100.0)
    nextNumber = 18;
else if (probability < (55.0 + 30.0) / 100.0)
    nextNumber = 1;
else
    nextNumber = 17;
Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
1

How about something like this (untested):

struct np
{
    int n;
    int p;
}

Create a List<np> and will it with value/percentage pairs (e.g. n = 18, p = 55).

Then just do the following to pick a number:

List<np> npl = new List<np>();
// (fill the list here)



int r = rnd.next(total_of_all_p_values); // get random number
int res = 0; // result
for(int i = 0; i < npl.Length(); r -= npl[i++].n)
{
    if(r < npl[i].p) // remaining vlaue is smaller than current percentage
    {
        res = npl[i].n;
        break;
    }
}
Mario
  • 35,726
  • 5
  • 62
  • 78
0

You could populate a List<T> with the appropriate number of each of the 3 numbers, and then randomize the List.

Community
  • 1
  • 1
devdigital
  • 34,151
  • 9
  • 98
  • 120