How does C#'s random number generator work? - c#

I was just wondering how the random number generator in C# works. I was also curious how I could make a program that generates random WHOLE INTEGER numbers from 1-100.

You can use Random.Next(int maxValue):
Return:
A 32-bit signed integer greater than or equal to zero, and less than
maxValue; that is, the range of return values ordinarily includes zero
but not maxValue. However, if maxValue equals zero, maxValue is
returned.
var r = new Random();
// print random integer >= 0 and < 100
Console.WriteLine(r.Next(100));
For this case however you could use Random.Next(int minValue, int maxValue), like this:
// print random integer >= 1 and < 101
Console.WriteLine(r.Next(1, 101);)
// or perhaps (if you have this specific case)
Console.WriteLine(r.Next(100) + 1);

I was just wondering how the random number generator in C# works.
That's implementation-specific, but the wikipedia entry for pseudo-random number generators should give you some ideas.
I was also curious how I could make a program that generates random WHOLE INTEGER numbers from 1-100.
You can use Random.Next(int, int):
Random rng = new Random();
for (int i = 0; i < 10; i++)
{
Console.WriteLine(rng.Next(1, 101));
}
Note that the upper bound is exclusive - which is why I've used 101 here.
You should also be aware of some of the "gotchas" associated with Random - in particular, you should not create a new instance every time you want to generate a random number, as otherwise if you generate lots of random numbers in a short space of time, you'll see a lot of repeats. See my article on this topic for more details.

I've been searching the internet for RNG for a while now. Everything I saw was either TOO complex or was just not what I was looking for. After reading a few articles I was able to come up with this simple code.
{
Random rnd = new Random(DateTime.Now.Millisecond);
int[] b = new int[10] { 5, 8, 1, 7, 3, 2, 9, 0, 4, 6 };
textBox1.Text = Convert.ToString(b[rnd.Next(10)])
}
Simple explanation,
create a 1 dimensional integer array.
full up the array with unordered numbers.
use the rnd.Next to get the position of the number that will be picked.
This works well.
To obtain a random number less than 100 use
{
Random rnd = new Random(DateTime.Now.Millisecond);
int[] b = new int[10] { 5, 8, 1, 7, 3, 2, 9, 0, 4, 6 };
int[] d = new int[10] { 9, 4, 7, 2, 8, 0, 5, 1, 3, 4 };
textBox1.Text = Convert.ToString(b[rnd.Next(10)]) + Convert.ToString(d[rnd.Next(10)]);
}
and so on for 3, 4, 5, and 6 ... digit random numbers.
Hope this assists someone positively.

so thats kind of easy if you just use it like
Random random = new Random();
int answer = random.Next(0);

Related

Why multiply Random.Next() by a Constant?

I recently read an article explaining how to generate a weighted random number, and there's a piece of the code that I don't understand:
int r = ((int)(rand.Next() * (323567)) % prefix[n - 1]) + 1;
Why is rand.Next being multiplied by a constant 323567? Would the code work without this constant?
Below is the full code for reference, and you can find the full article here: https://www.geeksforgeeks.org/random-number-generator-in-arbitrary-probability-distribution-fashion/
Any help is appreciated, thank you!!
// C# program to generate random numbers
// according to given frequency distribution
using System;
class GFG{
// Utility function to find ceiling
// of r in arr[l..h]
static int findCeil(int[] arr, int r,
int l, int h)
{
int mid;
while (l < h)
{
// Same as mid = (l+h)/2
mid = l + ((h - l) >> 1);
if (r > arr[mid])
l = mid + 1;
else
h = mid;
}
return (arr[l] >= r) ? l : -1;
}
// The main function that returns a random number
// from arr[] according to distribution array
// defined by freq[]. n is size of arrays.
static int myRand(int[] arr, int[] freq, int n)
{
// Create and fill prefix array
int[] prefix = new int[n];
int i;
prefix[0] = freq[0];
for(i = 1; i < n; ++i)
prefix[i] = prefix[i - 1] + freq[i];
// prefix[n-1] is sum of all frequencies.
// Generate a random number with
// value from 1 to this sum
Random rand = new Random();
int r = ((int)(rand.Next() * (323567)) % prefix[n - 1]) + 1; // <--- RNG * Constant
// Find index of ceiling of r in prefix array
int indexc = findCeil(prefix, r, 0, n - 1);
return arr[indexc];
}
// Driver Code
static void Main()
{
int[] arr = { 1, 2, 3, 4 };
int[] freq = { 10, 5, 20, 100 };
int i, n = arr.Length;
// Let us generate 10 random numbers
// according to given distribution
for(i = 0; i < 5; i++)
Console.WriteLine(myRand(arr, freq, n));
}
}
UPDATE:
I ran this code to check it:
int[] intArray = new int[] { 1, 2, 3, 4, 5 };
int[] weights = new int[] { 5, 20, 20, 40, 15 };
List<int> results = new List<int>();
for (int i = 0; i < 100000; i++)
{
results.Add(WeightedRNG.GetRand(intArray, weights, intArray.Length));
}
for (int i = 0; i < intArray.Length; i++)
{
int itemsFound = results.Where(x => x == intArray[i]).Count();
Console.WriteLine($"{intArray[i]} was returned {itemsFound} times.");
}
And here are the results with the constant:
1 was returned 5096 times.
2 was returned 19902 times.
3 was returned 20086 times.
4 was returned 40012 times.
5 was returned 14904 times.
And without the constant...
1 was returned 100000 times.
2 was returned 0 times.
3 was returned 0 times.
4 was returned 0 times.
5 was returned 0 times.
It completely breaks without it.
The constant does serve a purpose in some environments, but I don't believe this code is correct for C#.
To explain, let's look at the arguments to the function. The first sign something is off is passing n as an argument instead of inferring it from the arrays. The second sign is it's poor practice in C# to deal with paired arrays rather than something like a 2D array or sequence of single objects (such as a Tuple). But those are just indicators something is odd, and not evidence of any bugs.
So let's put that on hold for a moment and explain why a constant might matter by looking a small example.
Say you have three numbers (1, 2, and 3) with weights 3, 2, and 2. This function first builds up a prefix array, where each item includes the chances of finding the number for that index and all previous numbers.
We end up with a result like this: (3, 5, 7). Now we can use the last value and take a random number from 1 to 7. Values 1-3 result in 1, values 4 and 5 result in 2, and values 6 and 7 result in 3.
To find this random number the code now calls rand.Next(), and this is where I think the error comes in. In many platforms, the Next() function returns a double between 0 and 1. That's too small to use to lookup your weighted value, so you then multiply by a prime constant related the platform's epsilon value to ensure you have a reasonably large result that will cover the entire possible range of desired weights (in this case, 1-7) and then some. Now you take the remainder (%) vs your max weight (7), and map it via the prefix array to get the final result.
So the first error is, in C#, .Next() does not return a double. It is documented to return a non-negative random integer between 0 and int.MaxValue. Multiply that by 323567 and you're asking for integer overflow exceptions. Another sign of this mistake is the cast to int: the result of this function is already an int. And let's not even talk the meaningless extra parentheses around (323567).
There is also another, more subtle, error.
Let's the say the result of the (int)(rand.Next() * 323567) expression is 10. Now we take this value and get the remainder when dividing by our max value (%7). The problem here is we have two chances to roll a 1, 2, or 3 (the extra chance is if the original was 8, 9, or 10), and only once chance for the remaining weights (4-7). So we have introduced unintended bias into the system, completely throwing off the expected weights. (This is a simplification. The actual number space is not 1-10; it's 0 * 323567 - 0.999999 * 323567. But the potential for bias still exists as long that max value is not evenly divisible by the max weight value).
It's possible the constant was chosen because it has properties to minimize this effect, but again: it was based on a completely different kind of .Next() function.
Therefore the rand.Next() line should probably be changed to look like this:
int r = rand.Next(prefix[n - 1]) +1;
or this:
int r = ((int)(rand.NextDouble() * (323567 * prefix[n - 1])) % prefix[n - 1]) + 1;
But, given the other errors, I'd be wary of using this code at all.
For fun, here's an example running several different options:
https://dotnetfiddle.net/Y5qhRm
The original random method (using NextDouble() and a bare constant) doesn't fare as badly as I'd expect.

Get max from a sub array in C#

I have a question, lets say I have an array:
var array = new int[] { 7, 16, 4, 9, 865, 3, -8, 56};
I want to get the max value from index (lets say index 4), how do I do that?
Is there something like:
array.fromIndex(4).max()
also, I tried to go simple and did
(array + 4).max()
but get an error
"operator '+' cannot be applied"
Why is that?
Thank you!
also, I tried to go simple and did
(array + 4).max()
but get an error "operator '+' cannot be applied", why is that?
In C# array is not a pointer that you can calculate with. So the operator + is not defined to perform such an operation.
If you want to start searching the max value from a certain index on you can skip all the values up to this point:
int maxValue = array.Skip(4).Max();
EDIT:
Inspired by the suggested of #jdphenix in the comment:
If you want to have more control over the range where you want to search the maximum then the Take method could be of great help. This combination would allow you to set the range of your sub array:
var array = new int[] { 7, 16, 4, 9, 865, 3, -8, 56 };
int startIndex = 4;
int numberOfElements = 3;
array.Skip(startIndex).Take(numberOfElements).Max();
if you want to specify the start- and end-index it would look like this:
int startIndex = 4;
int endIndex = 7;
array.Skip(startIndex).Take(endIndex - startIndex).Max();

get "running average" of a list

Say I've got a list:
List<int> numbers = new List<int>();
and I'm trying to get the "running averages" of it. (Sorry, I don't really know how to call it).
For instance:
The first item in this list is 5, the average of 5 is 5, so the first average is 5.
The second item in this list is 7, the average of 5 and 7 is 6, so the second average is 6.
The third item in this list is 10, the average of 5, 7 and 10 is 7.3, so the third average is 7.3
And so on.
Those first average, second average etc are the averages I'm trying to get. How would I go about doing this? I've been searching the internet but honestly I'm not quite sure what I should be looking for. :(
try this:
string st = Console.ReadLine();
string[] strs = st.Split(' ');
List<int> numbers = new List<int>();
List<double> averages = new List<double>();
for (int i = 0; i < strs.Length; i++)
{
numbers.Add(int.Parse(strs[i]));
averages.Add(numbers.Average());
}
this will read the numbers from the standard input, the numbers are separated by space in input.
You can try something like this:
var averages = Enumerable.Range(1, numbers.Count)
.Select(x => numbers.Take(x).Average())
.ToList();
This will generate a sequence from 1 to numbers.Count. Then using Take it will get X element at each time (you can think X as an index, only difference is it starts from 1 and increases one by one up to the numbers.Count) starting from the first element then get their average.Put them into a list.
The lists
List<int> numbers = new List<int>();
List<double> averages = new List<double>();
test data
numbers.AddRange(new int[]{5, 7, 10});
// get average of current List
averages.Add(numbers.Average());
Such a list of averages all by itself usually doesnt mean much without some other data like number of elements, duration of time or something to qualify it.
This method is better suited when the moving average is not one for one with the values. For instance, the app stores values. Then periodically, say once a minute, the average is calculated and stored.
You need the "Running Average", not the average from the start over all items I assume?
The running average needs a number to tell how far back to look and one to tell how far forward to look.
This will give you the running average:
public List<double> GetRunningAverage(List<double> SourceList, int ItemsBefore, int ItemsAfter)
{
List<double> TargetList = new List<double>() { };
// Only makes sense if the list is > 1 of course
if (SourceList.Count > 1)
{
for (int i = 0; i < SourceList.Count; i++)
{
int LookBack =
(ItemsBefore > i ? i : ItemsBefore);
int LookForward =
(ItemsAfter < SourceList.Count - i
? ItemsAfter : SourceList.Count - i);
TargetList.Add(SourceList.GetRange(i - LookBack, LookBack + LookForward).Average());
}
}
else
{
TargetList.AddRange(SourceList);
}
return TargetList;
}
You can then use it like this:
List<double> FullList = GetRunningAverage(
new List<double>() { 100, 5, 5, 6, 23, 10, 56, 32, 54, 1, 3, 85, 65, 49, 22, 65, 32, 5, 2, 4, 5, 89, 110, 55, 6, 56, 57 },
3, // Looking back 3 items
3); // Looking forward 3 items

Best way to lookup numbers in multiples of 3's C#

I'm currently working on a project that requires me to overwrite services.
I have 3 lists. List1, List2 and List3. I want all my lists to take care of any numbers in multiples of 3's.
A count will come in. If the number is 1 go to List 1. If the number is 4, go to List1. If the number is 9 go to List 3.
For example:
List1 will deal with 1, 4, 7, 10, 13, 16 etc
List2 will deal with 2, 5, 8, 11, 14, 17 etc
List3 will deal with 3, 6, 9, 12, 15, 18 etc
I hope that makes sense.
Rather than setting up tables or cases, I'd prefer a simple mathematical approach.
Thanks
You need to use modular maths. To do this you just need something like:
int listNumber = input % 3;
This will output 0, 1 or 2 for any positive integer. 0 will in this case represent list 3.
How you then use this will depend on how your Lists are stored, etc. but hopefully should be a simple exercise.
Simply use Modulus function. It returns remainder from division operation.
int number = 4;
int result = number % 3;
here result will be 1 which was required and so on.
This is best way to lookup numbers in multiples of 3's C#
var lists = new[] {
new List<int>(),
new List<int>(),
new List<int>()
};
var listToDoStuffWith = lists[inputNumber % 3];
Something like
var listSelector = number % 3;
switch(listSelector)
{
case 0:
list3.add(number);
break;
case 1:
list1.add(number);
break;
case 2:
list2.add(number);
break;
}
0 would land into list3 as 0 % 3 == 0

Do you know a way to unsort an list or array?

I remember to see a method seems to buble sort, where can unsort items.
For example, I was trying to show randomize items from 0 to 10, using Random class. But I guess is not the best choice.
So, I guess creating an extension for IEnumberable, List or array, whatever can be a best way.
You are looking for a shuffle, a good example for randomized re-ordering is the Fisher-Yates Shuffle.
Here's an implementation by Jon Skeet in C#.
The algorithm that looks like bubble sort would be:
for i= 0:(len(x)-1):
j = random(i,len(x)-1)
swap(x[i],x[j])
Assume that random(a,b) returns a random integer c such that a<=c<=b.
And, this algorithm is called "Fisher Yates Shuffle".
FWIW, you cannot "truly" shuffle a big array with the standard inbuilt random number generators. A 21-item shuffle has a entropy of 65 bits, where as most RNGs are of 64 bits or 32 bits.
This will give you a random values from 0 to 10 (including 10):
int[] randomNumbers = Shuffle(Enumerable.Range(0, 11), new Random()).ToArray();
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random random)
{
T[] list = source.ToArray();
int count = list.Length;
while (count > 1)
{
int index = random.Next(count--);
T temp = list[index];
list[index] = list[count];
list[count] = temp;
}
return list;
}
you can use linq...
var result = Enumerable.Range(0,10).OrderBy( n=> Guid.NewGuid() )
Interesting problems,
I propose to leave work linq:
IEnumerable<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Random rnd = new Random();
list = list.Select(i => new { value = i, rank = rnd.Next(list.Count()) }).OrderBy(n => n.rank).Select(n => n.value);

Categories