So I am currently trying to test a function that uses a random function. In order to test it, I'm passing in a seed value to the C# Random function. (ie. System.Random)
My test cases involve using int.MaxValue and int.MinValue to get boundary testing. The max value of integer produces consistent and expected results. But when I try to use the min value the next keeps producing random results that are not predictable and therefore can't be tested.
I'm curious if this is expected or what the reasoning a seed is not producing predictable results. Am I missing something?
Thanks in advance.
Edit:
Supplying the code for reference. The methods are array extensions that I use in order to shuffle the array into a random order. I'm using the random class in order to get varied results and passing in my seed as an optional parameter to allow testing.
public static void Shuffle<T>(this T[] array, int seedValue = -1)
{
// Create the randomizer that will be needed
Random random = seedValue >= 0 ? new Random(seedValue) : new Random();
// Run the algorithm
for (int i = array.Length - 1; i > 0; i--)
{
// Get a random integer with a maximum of i
int r = random.Next(i);
// Swap the element at r with the element at i
array.Swap(r, i);
}
}
public static void Swap<T>(this T[] array, int indexOne, int indexTwo)
{
// Check if the indices that we were passed are the same index
if (indexOne == indexTwo)
{
return;
}
// Check that the first index is in range
if (indexOne < 0 || indexOne >= array.Length)
{
throw new ArgumentOutOfRangeException("indexOne", "The first index provided is out of the range of the array provided.");
}
// Check that the second index is in range
if (indexTwo < 0 || indexTwo >= array.Length)
{
throw new ArgumentOutOfRangeException("indexTwo", "The second index provided is out of the range of the array provided.");
}
// Swap the items
T temp = array[indexOne];
array[indexOne] = array[indexTwo];
array[indexTwo] = temp;
}
So those are the methods that are being tested. I'm passing the minvalue into the Shuffle function. And upon further investigation for myself, it seems to be occuring with any negative value. It seems to produce inconsistent results. I am currently working in the .NET 2.0. Old version I know, but I'm working inside Unity.
Here's your problem:
Random random = seedValue >= 0 ? new Random(seedValue) : new Random();
If you are passing a seed value less than zero, you are not using it at all,
So naturally, the random seed gets selected from the running computer's clock.
If you check the source code of the Random class, you can find the following line in the constructor:
int subtraction = (Seed == Int32.MinValue) ?
Int32.MaxValue : Math.Abs( Seed );
This check means that if the Seed is equal to Int32.MinValue, the MaxValue is used instead. It also means the results from both should be exactly the same.
Related
I want to generate a random number or null. So lets say i have the option to fill in a number or leave a field blank (null) and now i wna tot generate one of the two. Generating a random number is easy using the Random class but i'm not sure how to let mij function return null occasionally. I hope someone has a good idea in stead of always return null if the number generated is divisable through lets say 3 or another static number. the number that are generated will be used for indexes of arrays and the arrays are reasonably small. Lets say between 2 and 10 items.
User for example a negative one for null. Maybe like this:
Random r = new Random();
int? randomNumber;
randomNumber = r.Next(-1, 3); //put whatever range you want in here from negative to positive
if(randomNumber == -1)
{
randomNumber = null;
}
Following my comment above, I would suggest you generate a first random number between n options (based on how many odds you want the number to be null) and based on that outcome, decide to return null or a random number.
The function since can return a nullable int, must declare the type as nullable using int?.
this is an example using that strategy:
private void caller(){
Random rnd = new Random();
//generate 100 random numbers from a caller
for(int i=0;i<100;i++)
this.getNumber(rnd);
}
private int? getNumber(Random rnd, int oddsOfBeingNull = 2){
int nullOrNumber = rnd.Next(1, oddsOfBeingNull);
//if it's == 1, return null
if(nullOrNumber == 1)
return null;
//else return a random number between 1-100
return rnd.Next(1, 100);
}
}
This is a special edge case. The null scenario you wish to add to the possible results is something you will have to define its probability.
I think it is reasonable and quite easy to pre-define a range for which you will return null to the user.
Define this range based on the desired probability and add a simple range check after querying the random function.
something like this:
private double? Random()
{
var r = new Random();
var result = r.NextDouble();
if (result > 0.9)
return null;
return result;
}
I'm working on a football league fixture project on C# Console Application.
I'm trying to choose random teams from the array which contains the teams which plays at their home and away.
When I'm trying to generate 9 random numbers, only 8 numbers are generated and 0 are not, so the code can't break the for loop.
I suppose that the problem is that the if statement does not allow to generate the same number and int array's elements' default value is 0.
Here is the code and the output:
C# Code Output
int randomHome; //Random number genetator for choosing a random iteration value from home array which containss the teams which plays at their home
int randomAway; //Random number genetator for choosing a random iteration value from awayarray which containss the teams which plays at away
Random randomNum = new Random();
int[] randomHomeNumArray = new int[home.Length]; //array will hold the randomHome values and home array is the array which is holding the team's iteration values which plays at their home
int[] randomAwayNumArray = new int[away.Length]; //array will hold the randomAway values and away array is the array which is holding the team's iteration values which plays at away
for (int homeArrayCounter = 0; homeArrayCounter < randomHomeNumArray.Length; homeArrayCounter++)
{
randomHome = randomNum.Next(home.Length)
if (!randomHomeNumArray.Contains(randomHome) )
{
randomHomeNumArray[homeArrayCounter] = randomHome; //It will hold the randomHome values
Console.WriteLine(homeArrayCounter + ". iterasyon in Home " + randomHomeNumArray[homeArrayCounter]);
}
else
{
homeArrayCounter--;
}
}
Console.WriteLine("\n\n");
for (int awayArrayCounter = 0; awayArrayCounter < randomAwayNumArray.Length; awayArrayCounter++)
{
randomAway = randomNum.Next(randomAwayNumArray.Length);
if (!randomAwayNumArray.Contains(randomAway))
{
randomAwayNumArray[awayArrayCounter] = randomAway; //It holds the random valures from away array which contains the teams which plays at away
Console.WriteLine(awayArrayCounter + ". iterasyon in Away " + randomAwayNumArray[awayArrayCounter]);
}
else
{
awayArrayCounter--;
}
}
When you initalize an array, it has the value 0 by default for each index. When you are using the random number, it always skips 0 because it already exists.
You can try like this:-
for(int i= 0; i<randomHomeNumArray.Length; i++){
randomHomeNumArray[i] = -1;
}
for (int homeArrayCounter = 0; homeArrayCounter < randomHomeNumArray.Length; homeArrayCounter++)
{
do{
randomHome = randomNum.Next(home.Length);
} while(!randomHomeNumArray.Contains(randomHome));
randomHomeNumArray[homeArrayCounter] = randomHome; //It will hold the randomHome values
Console.WriteLine(homeArrayCounter + ". iterasyon in Home " + randomHomeNumArray[homeArrayCounter]);
}
It appears you're trying to just randomize arrays.
Try this instead:
Random randomNum = new Random();
int[] randomHomeNumArray = Enumerable.Range(0, home.Length).OrderBy(_ => randomNum.Next()).ToArray();
int[] randomAwayNumArray = Enumerable.Range(0, away.Length).OrderBy(_ => randomNum.Next()).ToArray();
That's it. Done.
Your problem is the default initialization of your arrays:
int[] randomHomeNumArray = new int[home.Length];
This creates an array filled with 0s, because 0 is the default value for int.
So your if condition
if (!randomHomeNumArray.Contains(randomHome))
is always false for 0 because 0 is already contained in the array.
You may initialize your arrays instead like this:
int[] randomHomeNumArray = Enumerable.Repeat(-1, home.Length).ToArray();
So you fill it with -1 instead of 0 and your if condition works.
Because int is not a null-able data type, by default, an int[] gets initialized with zeroes. So even if you think it's an empty array, it's actually an array with all elements set to zero.
To rectify the problem, you can consider using an int?[] (null-able int array) instead. Or, you can initialize the array with either a negative integer or some integer greater than the maximum inclusive upper bound. Better yet, to achieve what you want, in a better way, use the solution provided by #Enigmativity, and mark his answer accepted, if it helped.
So I'm trying to copy an array to a list in a randomized order, and it's "kind of" working, I'm getting a random order output except that it doesn't seem to be "completely" random, that is, there are certain sequences of numbers that seem to repeat many times they are specifically 1-9. Now they don't always appear in a sequence and the position of the sequence relative to the other numbers changes, but I am seeing them appear an abnormal amount of times for a "randomized list".
Here's my code:
class Program
{
static void Main(string[] args)
{
int[] originalDeck = new int[52];
for (int i = 1; i < originalDeck.Length+1; i++)
{
originalDeck[i-1] = i;
}
Random RNG = new Random();
List<int> split1 = originalDeck.OrderBy(x => x < RNG.Next(52)).ToList();
PrintList1(split1);
Console.ReadKey();
}
static void PrintList1(List<int> split)
{
foreach (int card in split)
{
Console.WriteLine(card);
}
}
}
What happens here is that you sort the array based on the probability of the number to be less than a random number between 0 and 51.
The OrderBy function in your case returns a boolean value of either True or False, the internal implementation works such that the sorted array will have all the false in the beginning followed by all the true. You can see this by sorting a list of Boolean values. In your case, you pick a random number between 0 and 51 and then compare it to your number. The probability of the check x < RNG.Next(52) to return True is much higher for small numbers and False for large numbers. Therefore you are actually putting the larger numbers at the beginning of the array and the smaller numbers at the end of the array with some randomness.
About the seed issue. It is not related directly since the seed is determined once when you create the Random instance.
I use this code to generate a random number.
Random R = new Random(0);
int Rand = R.Next(7);
but i get the same random number in each run of program.
Remove the 0 from the constructor and you'll get different random numbers.
If you pass a number to the constructor it's used as seed, by always specifying 0 you'll always get the same sequence.
You can specify an int32 which is random, but the easiest is to just not pass any parameter and you get a timebased seed
you have to change the seed of your random number generator object everytime you run your program, as what i've seen from you example, your current seed is 0, so you have to change it to something else if you want to get a different stream of random number... just a thought!
Seed your (pseudo)-random generator using a non-constant value, e.g. current time and date:
Random R = new Random(DateTime.Now.Ticks);
Read more about pseudo-random generators at Wikipedia.
Use time as initial seed of your PRNG.
You need to seed the random generator. You can use as follows:
Random R = new Random(DateTime.Now.Millisecond);
int Rand = R.Next(7);
Random number generators generate a new 'random' value based on the previous number generated. The seed is the initial value for this.
Seeding with the same value (like 0 in your example code) basically tells the random number generator to start with the same number each time. Having the exact same random number generated each time means your code becomes restartable. Example: Simulations use this to restart the simulation with changed parameters, but with the same 'data set'.
Another example:
I want to send myself a motivational message each day. Sometimes the messages are garbled. Being able to rerun the script, producing the same message again and again during a day, makes fixing this simple. In Perl code this means:
# By initialising the random generator with the day number since
# the epoch, we get the same quote during one day.
srand(time()/(24*3600));
my $i = int(rand(#messages));
If you want to produce different numbers each time, you will have to set this seed to something random. The options are many, like time, PID, delay between two keystrokes by the user, some value derived from the ethernet interface, etc. or more likely a combination of the above like time*PID.
Hope this clarifies the idea behind the concept of a random number seed value.
if we want a random number between 1 and 100 the code would look like this:
RandomNumberGenerator.GetRandomInt(1, 100)
The most secure way to generate random number is to use the System.Security.Cryptography.RandomNumberGenerator class.
Here is an example that will generate a number between 1 and 100;
public Number Rand()
{
byte[] Salt = new byte[8];
System.Security.Cryptography.RandomNumberGenerator.Create().GetBytes(Salt);
decimal result = 0;
foreach (byte b in Salt)
{
result = result * 255 + b;
}
while (result > 100)
{
result /= 10;
}
return result
}
Complete Code:
public static class RandomHelper
{
static object _myLock = new object();
static Random _random = new Random();
public static int RandomNumber(int min, int max)
{
lock (_myLock)
{
if (min == max)
return min;
if (min > max)
return _random.Next(max, min);
return _random.Next(min, max);
}
}
You need to seed the Random class with something more variable than 0. I normally use DataTime.Now.Ticks or you could use a new Guid's integer value.
Ok so I have a dice throw app...
When I step through the code it functions normally and 'results' contains the correct number of throw results and they appear to be random, when I leave the code to run and do exactly the same thing it produces a set of identical numbers.
I'm sure this is a logical error I cannot see but fiddling with it for hours hasnt improved the situation, so any help is much appriciated. :)
class Dice
{
public int[] Roll(int _throws, int _sides, int _count)
{
Random rnd = new Random();
int[] results = new int[_throws];
// for each set of dice to throw pass data to calculate method
for (int i = 0; i < _throws; i++)
{
int thisThrow = Calculate(_sides, _count);
//add each throw to a new index of array... repeat for every throw
results[i] = thisThrow;
}
return results;
}
private int Calculate(int _sides, int _count)
{
Random rnd = new Random();
int[] result = new int[_count];
int total = 0;
//for each dice to throw put data into result
for (int i = 0; i < _count; i++)
{
result[i] = rnd.Next(1, _sides);
}
//count the values in result
for (int x = 0; x < _count; x++)
{
total = total + result[x];
}
//return total of all dice to Roll method
return total;
}
}
First mistake: Never use multiple instances of Random, use a single instance, and pass that along with the other parameters.
When you create "Random rnd = new Random();" it is seeded by the current time. When you debug your code (which takes time) it will be seeded differently each time.
Create 1 instance of Random, and reference that everywhere.
You're creating a random class every time you need to create a number. Doing this will give you the nutty results.
See here: FROM MSDN
This problem can be avoided by creating a single Random object rather than multiple ones.
To improve performance, create one Random object to generate many random numbers over time, instead of repeatedly creating a new Random objects to generate one random number.
E.g. create a private instance of Random...
In addition to what has been mentioned before...
Use Random for things like dice, card games, choosing random images and so forth. If you ever need to create a random number for security sake, use System.Security.Cryptography.RandomNumberGenerator. This simple example shows creating a random integer.
RandomNumberGenerator gen = RandomNumberGenerator.Create();
byte[] myBytes = new byte[4];
gen.GetBytes(myBytes);
int myValue = (BitConverter.ToInt32(myBytes, 0));
DO NOT use this unless you have a security need. The performance is less than that of the Random class. I suppose you could use this to seed Random but that might be overkill.
EDIT: It occurred to me that I had never tested this. A quick performance test showed the following:
1,000,000 random numbers:
RandomNumberGenerator: 2.6 seconds
Random: .015 seconds.
So Random is about 150 times faster.
Give the constructor Random a seed. That's the problem.
http://msdn.microsoft.com/en-us/library/aa329890%28VS.71%29.aspx
Random r = new Random(DateTime.Now.Millisecond);