c# probability and random numbers - c#

I want to trigger an event with a probability of 25% based on a random number generated between 1 and 100 using:
int rand = random.Next(1,100);
Will the following achieve this?
if (rand<=25)
{
// Some event...
}
I thought I would use a number between 1 and 100 so I can tweak the probabilities later on - e.g. adjust to 23% by using
if (rand<=23) {...}

The biggest error you are making is it should be random.Next(0,100) as the documentation states
minValue: The inclusive lower bound of the random number returned.
maxValue: The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue.
Emphisis mine, exclusive means it does not include number you passed in, so my code generates the range 0-99 and your code generates the range 1-99.
So change your code to
int rand = random.Next(0,100)
if (rand < 25) //25%
{
// Some event...
}
//other code
if (rand < 23) //23%
{
// Some event...
}
The change from <= to < is because you are now using the exclusive upper bounds range

The second argument of Next(int, int) is the exclusive upper bound of the desired range of results. You should therefore use this:
if (random.Next(0, 100) < 25)
or, if you must use 1-based logic,
if (random.Next(1, 101) <= 25)

You can also use this code (usually for percentage calculations double between 0 and 1 is used):
double rand = random.NextDouble();
if(rand < .25)
{
...

Related

Setting final value to zero makes the program not count or output, but setting to the lowest value does

This is practice for a separate larger program, just a little console output showing how many of certain values are used. For some reason if I set the final while num value to zero, it won't output anything in the console. If I set it to 20 it will output, count the hundreds and the 20's, but skips the fact that there is a 50 because the while value won't allow it to go below 20. I tried while num is >= to zero as well. At > zero or >=, I would expect it would count the 50 and output 4 100's, 1 50 and 0 20's. I arbitrarily set the while value to 10 and it still gave 2 20's and the hundreds, but set at 1 it didn't output again, same as when set to zero. Before I can incorporate the logic into the bigger program which has a lot more values and returns I imagine I'll need to understand where I'm failing. I looked into recursion and trackback algorithms and they were just a bit beyond where I'm at yet. I did wonder if I could use modulus too. That's off track tho, I'm most curious about why that while value won't allow itself to be set to greater than or greater than/equal to zero.
using System;
namespace dollars_back_test
{
class Program
{
static void Main(string[] args)
{
int num = 450, hundos = 0, fifties = 0, twenties = 0;
do
{
if (num > 100)
{
num -= 100;
hundos++;
}
else if (num > 50)
{
num -= 50;
fifties++;
}
else if (num > 20)
{
num -= 20;
twenties++;
}
} while (num > 20);
Console.WriteLine($"Dispensing {hundos} 100's, {fifties} 50's, {twenties} 20's.");
Console.ReadLine();
}
}
}
I'm not sure I correctly understand the issue, but I believe what your asking is why the while loop is not printing any 50's. This is because you are checking if number is bigger than 50, but since you subtract 100 four times the values shall be:
1st loop: num 450
2nd loop: num 350
3rd loop: num 250
4th loop: num 150
5th loop: num 50 --> explenation: number isn't larger than 50, it is >= 50, that's why it will continue with printing the num>20 two times until 10 remains.
6th loop: num 30
7th loop: num 10
To solve this issue you can simply replace this:
num>50
by
num>=50
if that's what you would like to see. Then it will print the 50's.

Math.NET CryptoRandomSource Next is Biased

I am developing a gaming platform that is subject to heavy regulatory scrutiny. I chose Math.NET because it seemed like a good fit. However I have just received this comment back from our auditors.
Comments please if this is accurate and how it can be resolved?
In RandomSource(), Next(int, int) is defined as follows:
public override sealed int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue);
}
if (_threadSafe)
{
lock (_lock)
{
return (int)(DoSample()*(maxValue - minValue)) + minValue;
}
}
return (int)(DoSample()*(maxValue - minValue)) + minValue;
}
This creates a bias in the same way as before. Using an un-scaled value from the RNG and multiplying it by the range without previously eliminating the bias (unless the range is a power of 2, there will be a bias ).
Update: The implementation of Next(minInclusive, maxExclusive) has been changed in Math.NET Numerics v3.13 following this discussion. Since v3.13 it is no longer involving floating point numbers, but instead samples integers with as many bits as needed to support the requested range (power of two) and rejects those outside of the actual range. This way it avoids adding any bias on top of the byte sampling itself (as provided e.g. by the crypto RNG)
Assumption: DoSample() returns a uniformly distributed sample in the range [0,1) (double precision floating point number).
Multiplying it with the range R=max-min will result in a uniformly distributed sample in the range [0,R). Casting this to an integer, which is essentially a floor, will result in a uniformly distributed discrete sample of one of 0,1,2,...,R-1. I don't see where the fact that R is even, odd, or a power of two may affect bias in this step.
A few runs to compute 100'000'000 samples also do not indicate obvious bias, but of course this is no proof:
var r = new CryptoRandomSource();
long[] h = new long[8];
for (int i = 0; i < 100000000; i++)
{
h[r.Next(2,7)]++;
}
0
0
19996313
20001286
19998092
19998328
20005981
0
0
0
20000288
20002035
20006269
19994927
19996481
0
0
0
19998296
19997777
20001463
20002759
19999705
0
I've come up with this solution for a value between 0 and max inclusive. I'm no maths expert so comments welcome.
It seems to satisfy the regulatory spec I have which says
2b) If a particular random number selected is outside the range of equal distribution of re-scaling values, it is permissible to discard that random number and select the next in sequence for the purpose of re-scaling."
private readonly CryptoRandomSource _random = new CryptoRandomSource();
private int GetRandomNumber(int max)
{
int number;
var nextPowerOfTwo = (int)Math.Pow(2, Math.Ceiling(Math.Log(max) / Math.Log(2)));
do
{
// Note: 2nd param of Next is an *exclusive* value. Add 1 to satisfy this
number = _random.Next(0, nextPowerOfTwo + 1);
} while (number > max);
return number;
}

Random number issue with Next method (.NET Framework)

I need to generate a lot of random numbers which must be anywhere between 1 and int.MaxValue. The arguments passed to the Next method of the Random class are not always the same. In one senario the arguments might be as follows:
Next(1, int.MaxValue);
In another they might as well be:
Next(1, 2);
The issue here is that whenever you pass values like 1 and 2 or 99 and 100, the lower number is always the "random" number returned by the method. The reason for this is because the method subtracts 1 from the maximum value (unless min and max are the same) and then gives you the random number. How would I go about generating a range of random numbers within a range of numbers, as stated above, without getting this predictable outcome?
You would need to pass the inclusive upper bound + 1, ie:
var result = rand.Next(1, 2+1); // Returns 1 or 2
var result2 = rand.Next(99, 101); // Returns 99 or 100
Note that this won't work for int.MaxValue, of course. There is no way to have Random directly return int.MaxValue. To get a [0,int.MaxValue] result, you would need to do:
var result = rand.Next(-1, int.MaxValue) + 1;
The upper bound is exclusive, not inclusive. Given that, the range [1,2) only contains one number, 1, not two.
From the documentation, the first parameter to Next(int, int) is "The inclusive lower bound", while the second is "The exclusive upper bound".
If you want to generate a random number that might be 1 or 2, you should use the following call:
rand.Next(1, 3)
Try this
using System;
namespace ConsoleApplication3
{
class Program
{
static readonly Random r = new Random();
static void Main(string[] args)
{
for (int i = 2; i <= 100; i++)
{
Console.WriteLine(GetRandom(i));
}
}
private static int GetRandom(int i)
{
return 1 + (r.Next(int.MaxValue)%i);
}
}
}
Cheers.
You can get int.MaxValue by adding 1 after getting random int:
var result = rand.Next(1, int.MaxValue) + 1;
How about a method that takes the lower and upper limits and gives you what you're looking for?
Example:
public int GetRandom(int lower, int upper)
{
return upper == int.MaxValue ? rand.Next(lower - 1, upper) + 1 : rand.Next(lower, upper + 1);
}
If the upper limit is int.MaxValue, it shifts the range down by 1 and then adds it back after it gives the random number. Otherwise, it adds 1 to the upper limit and then gives you the random number.
Then when you use it, you'll just do something like:
var randomOne = GetRandom(1, 2);
var randomTwo = GetRandom(99,int.MaxValue);

Selecting a number from natural number < n excluding a possibility

Given n natural number starts from 0, and b which is a number in between 0 to n
I wish to randomly select a number excluding b.
Say n is 5
then The number to be selected is {0,1,2,3,4,5}
say b is 4,
then my random selection is from {0,1,2,3,5}
A way to do this is to do a while loop, until the random.nextInteger() does not find a 4.
Is there a easy to to do this other than using a while loop?
I would write a simple extension:
// N.B. : min is inclusive, max is exclusive; so range is: [min,max) - {toExclude}
public static int Next(this Random rand, int min, int max, int toExclude)
{
int v = rand.Next(min, max - 1);
if (v < toExclude)
return v;
return v + 1;
}
Usage:
var random = new Random();
var val = random.Next(0,6,4); // 6 because max is exclusive in C# random.Next()
Your approach is the best in my optinion. It is simple and elegant, and even for m=2 it is O(1) on average (The expected number of redraws is 1/2 + 1/4 + 1/8 + .... < 1).
If you want to avoid the worst case of infinite loop there is an alternative, though I doubt it will have real performance impact.
draw a random double in range [0,1]. let it be d. If d < b/m: draw a number in range [0,b) and return it.
Else (d > b/m) - draw a random number in range [b+1,m] and return it.
Note, it is indeed uniform distributed because:
There are m+1 numbers in range 0,...,m, but only m "valid" numbers (excluding b).
There are b numbers in range 0,1,...,b-1 - so the probability of the number being in this range assuming uniform distribution is b/m - which is exactly P(d < b/m).
In java it will look similar to this:
int m = 5, b = 4;
Random r = new Random();
double d = r.nextDouble();
if (d < ((double)b)/m) {
System.out.println(r.nextInt(b));
} else {
System.out.println(r.nextInt(m-b) + b + 1);
}
Here is another approach if you prefer:
import random
def random_unifrom(n,b):
assert b < n and n > 0 and b > 0
nMinusOneList = [i for i in range(n) if i != b]
lSize = len(nMinusOneList)
randIndex = random.randint(0, lSize-1)
return nMinusOneList[randIndex]
I wrote this in python just for simplicity.
creating the nMinusOneList has complexity of O(n).
returning the random index complexity depends on the random function you are using.
At the end, you loose nothing if you take this approach instead of a while loop, but even if you use the while loop approach, if the random function is random (!!) then you should not have a problem. However, my approach above excludes the number you do not need from the very beginning.
In C#, the one line I use in python might be a couple of lines which consists of a for loop on the range 0 to n, with a condition that the x (for loop index) does not equal to b, in building the list, and then you will have the list that excludes b.

How to convert number to next higher multiple of five?

I am coding a program where a form opens for a certain period of time before closing. I am giving the users to specify the time in seconds. But i'd like this to be in mutliples of five. Or the number gets rounded off to the nearest multiple.
if they enter 1 - 4, then the value is automatically set to 5.
If they enter 6 - 10 then the value is automatically set to 10.
max value is 60, min is 0.
what i have, but i am not happy with this logic since it resets it to 10 seconds.
if (Convert.ToInt32(maskedTextBox1.Text) >= 60 || Convert.ToInt32(maskedTextBox1.Text) <= 0)
mySettings.ToastFormTimer = 10000;
else
mySettings.ToastFormTimer = Convert.ToInt32 (maskedTextBox1.Text) * 1000;
use the Modulus Operator
if(num % 5 == 0)
{
// the number is a multiple of 5.
}
what about this:
int x = int.Parse(maskedTextBox1.Text)/5;
int y = Math.Min(Math.Max(x,1),12)*5; // between [5,60]
// use y as the answer you need
5 * ((num - 1) / 5 + 1)
Should work if c# does integer division.
For the higher goal of rounding to the upper multiple of 5, you don't need to test whether a number is a multiple. Generally speaking, you can round-up or round-to-nearest by adding a constant, then rounding down. To round up, the constant is one less than n. Rounding an integer down to a multiple of n is simple: divide by n and multiply the result by n. Here's a case where rounding error works in your favor.
int ceil_n(int x, int n) {
return ((x+n-1) / n) * n;
}
In dynamic languages that cast the result of integer division to prevent rounding error (which doesn't include C#), you'd need to cast the quotient back to an integer.
Dividing by n can be viewed as a right-shift by 1 place in base n; similarly, multiplying by n is equivalent to a left-shift by 1. This is why the above approach works: it sets the least-significant digit of the number in base n to 0.
2410=445, 2510=505, 2610=515
((445+4 = 535) >>5 1) <<5 1 = 505 = 2510
((505+4 = 545) >>5 1) <<5 1 = 505 = 2510
((515+4 = 605) >>5 1) <<5 1 = 605 = 3010
Another way of zeroing the LSD is to subtract the remainder to set the least significant base n digit to 0, as Jeras does in his comment.
int ceil_n(int x, int n) {
x += n-1;
return x - x%n;
}

Categories

Resources