Firstly you should convert your chance into a normalized value between 0.0 and 1.0. This is the mathematical notion of a probability.
For your case, this would give you double probability = 0.005;
.
Then you can do the following:
if (rng.NextDouble() < probability)
{
...
This works because Random.NextDouble()
returns a random number evenly distributed within the half-open interval [0.0, 1.0)
(i.e. up to but not including 1.0
.)
So if your probability is 0.0
the body of the if
will never be executed, and if your probability is 1.0
then it will always be executed.
The advantage of using a normalised probability is that it works with any probability, and not just with integral probabilities.
If you do happen to have a percentage probability, you convert it to a normalised one very simply - by dividing it by 100.0
.
Addendum:
There's little advantage to using Random.Next(int min, int max)
instead, because that only works for integral probabilities. And behind the scenes, Random.Next(int min, int max)
is implemented like this:
public virtual int Next(int minValue, int maxValue) {
if (minValue>maxValue) {
throw new ArgumentOutOfRangeException("minValue",Environment.GetResourceString("Argument_MinMaxValue", "minValue", "maxValue"));
}
Contract.EndContractBlock();
long range = (long)maxValue-minValue;
if( range <= (long)Int32.MaxValue) {
return ((int)(Sample() * range) + minValue);
}
else {
return (int)((long)(GetSampleForLargeRange() * range) + minValue);
}
}
And NextDouble()
is implemented as:
public virtual double NextDouble() {
return Sample();
}
Note that both these implementations call Sample()
.
Finally I just want to note that the built-in Random class isn't particularly great - it doesn't have a very long period. I use a RNG based on a 128-bit XOR-Shift which is very fast and generates very "good" random numbers.
(I use one based on this XORSHIFT+ generator.)