简体   繁体   中英

Weighted Random Number Generation in C#

Question

How can I randomly generate one of two states, with the probability of 'red' being generated 10% of the time, and 'green' being generated 90% of the time?

Background

Every 2 second either a green or a red light will blink.

This sequence will continue for 5 minutes.

The total number of occurrences of a blinking light should be 300.

Random.NextDouble returns a number between 0 and 1, so the following should work:

if (random.NextDouble() < 0.90)
{
    BlinkGreen();
}
else
{
    BlinkRed();
}

Either

Random rg = new Random();

int n = rg.Next(10); 
if(n == 0) {
    // blink red
}
else {
    // blink green
}

or

Random rg = new Random();

double value = rg.NextDouble();
if(value < 0.1) {
    // blink red
}
else {
    // blink green
}

This works because Random.Next(int maxValue) returns a uniformly distributed integer in [0, maxValue) and Random.NextDouble returns a uniformly distributed double in [0, 1) .

The other answers will definitely work if you need a random distribution that favors 90% green.

However, if you need a precise distribution, something like this will work:

void Main()
{
    Light[] lights = new Light[300];
    int i=0;
    Random rand = new Random();
    while(i<270)
    {
        int tryIndex = rand.Next(300);
        if(lights[tryIndex] == Light.NotSet)
        {
            lights[tryIndex] = Light.Green;
            i++;
        }
    }
    for(i=0;i<300;i++)
    {
        if(lights[i] == Light.NotSet)
        {
            lights[i] = Light.Red;
        }
    }

    //iterate over lights and do what you will
}


enum Light
{
    NotSet,
    Green,
    Red
}
public class NewRandom
{
    private static Random _rnd = new Random();
    public static bool PercentChance(int percent)
    {
        double d = (double)percent / 100.0;
        return (_rnd.NextDouble() <= d);
    }
}

To use:

if (NewRandom.PercentChance(10))
{
    // blink red
}
else
{
    // blink green
}

Building on Michaels answer, but adding further context from the question:

public static void PerformBlinks()
{
    var random = new Random();
    for (int i = 0; i < 300; i++)
    {
        if (random.Next(10) == 0)
        {
            BlinkGreen();
        }
        else
        {
            BlinkRed();
        }
        // Pause the thread for 2 seconds.
        Thread.Sleep(2000);
    }
}

I'm guessing you have the timing part down (so this code doesn't address that). Assuming "nice" division, this will generate 10% reds and 90% greens. If the exactness isn't important, Michael's answer already has my vote.

static void Main(string[] args)
{
    int blinkCount = 300, redPercent = 10, greenPercent = 90;
    List<BlinkObject> blinks = new List<BlinkObject>(300);

    for (int i = 0; i < (blinkCount * redPercent / 100); i++)
    {
        blinks.Add(new BlinkObject("red"));
    }

    for (int i = 0; i < (blinkCount * greenPercent / 100); i++)
    {
        blinks.Add(new BlinkObject("green"));
    }

    blinks.Sort();

    foreach (BlinkObject b in blinks)
    {
        Console.WriteLine(b);
    }
}

class BlinkObject : IComparable<BlinkObject>
{
    object Color { get; set; }
    Guid Order { get; set; }

    public BlinkObject(object color)
    {
        Color = color;
        Order = Guid.NewGuid();
    }

    public int CompareTo(BlinkObject obj)
    {
        return Order.CompareTo(obj.Order);
    }

    public override string ToString()
    {
        return Color.ToString();
    }
}
var random = new Random();
for (var i = 0; i < 150; ++i) {
  var red = random.Next(10) == 0;
  if (red)
    // ..
  else
    // Green
}

random.Next(10) will randomly return the numbers 0..9 and there is 10% chance of it returning 0.

If you want these just to look random, you might want to implement shuffle bag

http://web.archive.org/web/20111203113141/http://kaioa.com:80/node/53

and

Need for predictable random generator

This way the blinking period should look more natural and you can simply implement the restricted number of blinks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM