Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get a single random number from multiple possible ranges?

Tags:

c#

random

I would like to be able to generate a (pseudo)random number from n possible ranges, where a range is x, y and x < y. For example, executing this code:

for(int i = 0; i < 10; i++)
{
    Console.Write(Random.NextRanges(new Range(1, 6), new Range(10, 16), new Range(20, 31)) + " ");
}

will produce something like:

3 12 5 22 1 27 29 5 10 24

The signature of the method NextRanges is:

public static int NextRanges(params Range[] ranges)

And Range is defined as:

public struct Range
{
    public int X;
    public int Y;

    public Range(int x, int y)
    {
        if (x >= y) throw new ArgumentException("x must be less than y.");
        X = x;
        Y = y;
    }
}

The only thing I'm not sure on is how to implement NextRanges, what the most efficient way or the most random way is (I know random can be tricky sometimes). Would you choose a random Range and then use Random.Next() on that? Or would you keep choosing random numbers until you got one that was within each of the ranges?

Is it also possible to weight the ranges so that a range of 0-100 has far more weight than a range of 100-102, for example?

like image 288
qJake Avatar asked Dec 26 '13 20:12

qJake


1 Answers

Would you choose a random Range and then use Random.Next() on that?

No, because that would give numbers in shorter ranges more weight. For example, if one range contains a single number 42 and the other range contains 10,000 numbers, then 42 would be generated roughly 50% of the time.

Or would you keep choosing random numbers until you got one that was within each of the ranges?

No, because that would not be the too efficient. For example, if the first range is [1..3] and the second range is [200,000..200,001], getting a number in one of these ranges would take a while.

I would implement a Size property on the range, compute the total size, generate an int in the range index = [0..TotalSize-1], and then picked the item at the index as if all numbers in your ranges were numbered sequentially.

For example, in your ranges TotalSize would be 6+7+12=25. First, I would generate a random number in the range [0..24], say, 15. I would then see that 15 falls in the third range, so I'd return 21.

This would give each range a weight proportional to its size. If you would like to assign specific weights to your ranges, the algorithm would be different: you would compute an equivalent of TotalRange by multiplying the actual size by the weight of the range, and totaling up the products. You would then generate a number in the range of that weighted sum, pick the range by working backward from that random number, and then dividing out the weight of the specific range to obtain the position of the random item in the range.

like image 96
Sergey Kalinichenko Avatar answered Nov 01 '22 15:11

Sergey Kalinichenko