How to use the C# random method most effectively? [duplicate] - c#

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 9 years ago.
I have been able to use the random method to accomplish most of my tasks in trying to populate labels and RadioButtonList Items randomly to create a 5 question quiz.
The code generates a good blend of questions given the large pool it draws from.
However, the inner code for randomly populating the RadioButtonList Items is acting funny.
When I throw in breakpoints at my while loop and run it step by step the answers are populated in different order on every next question.
But when I simply open up the browser and run it from the Sharepoint website I have it deployed to,
the answers follow the same order sequence on every next question/all questions.
Note: It does however throw unique orders on page refresh; in other words when I start the quiz again.
I cant seem to figure out the hitch for the life of me.
Could use a few sets of eyes.
Here is the code thus far: Please advise
public void LoadQuestions()
{
try
{
SPWeb thisWeb = SPContext.Current.Web;
SPList oSPList = thisWeb.Lists["QuestionsAndAnswers"];
SPListItemCollection oSPListItemCollection = oSPList.Items;
Random rand = new Random();
List<int> tempStore = new List<int>();
List<int> tempStore2 = new List<int>();
int tempValue = 0;
//int tempValue2 = 0;
int icount = 1;
int iMax = oSPListItemCollection.Count;
//int icount2 = 0;
//int iMax2 = oSPListItemCollection.Count;
SPListItem thisItem;
Label thisQuestion;
Label thisCorrectAnswer;
RadioButtonList thisAnswers;
while (icount < 6)
{
tempValue = rand.Next(1, iMax);
if (tempStore.Exists(value => value == tempValue))
continue;
else
{
tempStore.Add(tempValue);
thisQuestion = (Label)UpdatePanelMaster.FindControl("Question" + icount.ToString());
thisItem = oSPListItemCollection[tempValue];
thisQuestion.Text = icount + ". " + thisItem["Question"].ToString();
thisCorrectAnswer = (Label)UpdatePanelMaster.FindControl("CorrectAnswer" + icount.ToString());
thisCorrectAnswer.Text = thisItem["CorrectAnswer"].ToString();
thisAnswers = (RadioButtonList)UpdatePanelMaster.FindControl("RadioButtonList" + icount.ToString());
//Entering code to handle random answer arrangements
//This code works ok when run in a step by step debug fashion but no when deployed and run from the website directly.
Missing/Changes required?
int tempValue2;
int Icounter = 0;
string[] AnswerArr = new string[] { thisItem["CorrectAnswer"].ToString(), thisItem["IncorrectAnswer1"].ToString(), thisItem["IncorrectAnswer2"].ToString(), thisItem["IncorrectAnswer3"].ToString() };
Random rand2 = new Random();
while (Icounter < 4)
{
tempValue2 = rand2.Next(0, 13);//max number of items in the array
decimal toCeilingVar = tempValue2 / 4;
int fraction = Convert.ToInt32(System.Math.Ceiling(toCeilingVar));
string tempArrValue = AnswerArr[fraction];
if (thisAnswers.Items.FindByValue(tempArrValue) == null)
{
//add new value because the current value is not in the list
thisAnswers.Items.Add(tempArrValue);
Icounter++;
tempArrValue = string.Empty;
}
tempValue2 = 0;
toCeilingVar = 0;
fraction = 0;
//End Random Answer handling
}
tempValue = 0;
icount++;
}
}
}
//End random question handling
catch (Exception ex)
{
throw ex;
}
}

The problem is (inside the loop):
Random rand2 = new Random();
The Random class is, if no explicit seed is provided, seeded using the time. If you create multiple instances in a tight loop, they will often be close enough (in time) together that they have the same seed. This means they will all generate the same sequence of pseudo-random numbers. Two options:
lose the inner Random instance (rand2) completely - just use the single outer instance (rand); using more Random instances does not increase the randomness
use the outer instance to seed the inner instance
I'd only use the latter if there was a good reason, for example parallelism

Probably what is happening here is that when run in production, the line Random rand2 = new Random() is called several times in a very short interval of time, so each instance will have the same initial seed value. The default constructor for Random uses a time-based seed with fairly low resolution in my experience.
To solve this, I would just use the single rand variable to generate all random numbers, or initialize rand2 outside the outermost loop.

Related

For loop advancing too quickly without generating random strings properly [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 6 years ago.
So I coded a quick program to test how much difference it would make (in terms of processing speed) to check a boolean inside a foreach statement compared to checking it in a conditional statement outside of the loop. To test this I made a function generate random strings and add them to a list, but the for loop that generates the strings seems to advance too quickly without generating different strings in ever repetition. To fix this I added a Thread.Sleep(15) (15 milliseconds seems to be the minimum required to generate a different string in every repetition).
My question is this: is it possible to fix this issue without a Thread.Sleep(15)? Waiting 15 milliseconds between every repetition makes it so that the program takes a way bigger amount of time to run, which makes it highly unpractical for it's purpose (if I want to get statistically relevant data I'd have to run it around 10 thousand times for each option (the "good" and the "bad" way)). Here's the for loop in question:
for (int i = 0; i < 1000; i++) {
var stringChars = new char[8];
var random = new Random();
for (int n = 0; n < stringChars.Length; n++)
{
stringChars[n] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
data.Add(finalString);
Thread.Sleep(15);
}
The problem you are getting is that you are recreating the Random class each time you iterate the loop.
The reason this is a problem is because the default seed for the Random class is the current system timestamp, which on repeated iterations could well be the same value.
Creating the Random outside of the for loop will ensure that a pseduo-random sequence is generated as you would expect.
Try this:
var random = new Random();
for (int i = 0; i < 1000; i++) {
var stringChars = new char[8];
for (int n = 0; n < stringChars.Length; n++)
{
stringChars[n] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
data.Add(finalString);
}

Looping through a method call too fast? [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
I am calling a method instance called buy. My method randomly generates a string of digits and numbers. My for loop appears to be going to fast for the method to change the string because I get the same string like 2-3 times in a row before getting a new string. when i add a System.Threading.Thread.Sleep(100); I am getting random number like the way it is supposed to be. The problem is that it is way too slow and i feel like there must be a better way. is there a way to get random string each time without invoking the Sleep() method?
for (int i = 0; i < exit; i++)
{
ticket = buy.SetNum();
Console.WriteLine("Wellcome Mr.Nissan. The winning numbers for Lotto max are:");
Console.WriteLine(ticket);
System.Threading.Thread.Sleep(25);
}
Yes, this is a problem with your random number generator - not with the code you posted in the question.
consider the following:
public int GenRandomNum()
{
var r = new Random();
return r.Next()
}
You are generating a new random class based on the same seed if you call it in the same tick, and it will generate the same number. Moving the random initialization out side of the method will fix the problem, like so:
private Random _rand = new Random();
public int GenRandomNum()
{
return _rand .Next()
}
You haven't included the code that actually creates the random number but I suspect you're creating a new instance of the random number generator each time around the loop.
What you need to do instead, is create one instance of the random number generator (outside of the loop) and reuse it for each random number generator .Next() call.
Move the random number generation into into the loop:
var rnd = new Random();
for (int i = 0; i < exit; i++)
{
var ticket = rnd.Next();
Console.WriteLine("Wellcome Mr.Nissan. The winning numbers for Lotto max are:");
Console.WriteLine(ticket);
}
I can't tell you why exactly your posted code wasn't working without seeing the buy.SetNum(); method code.

Code For Random not working properly [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
I am creating a random function to give me four random values of A,B,C,D and the sign(+,-). The problem is the code generates all same values and the output I get has only A=B=C=D=x where x is any random value generated by the code. Also I tried to put a breakpoint and debug it, it works just fine no problems but as soon as I remove the break point the same issue occurs. Can anyone please tell me where am I going wrong. The code is as follows:
public void RandomQuestionGenerate()
{//all the variables(A,B,C,D,sign1,sign2) are globally defined
Random FirstNo = new Random();
A = FirstNo.Next(0, 10);
Random SecondNo = new Random();
TextA.Text = A.ToString();
B = SecondNo.Next(0, 10);
Random ThirdNo = new Random();
TextB.Text = B.ToString();
C = ThirdNo.Next(0, 10);
Random FourthNo = new Random();
TextC.Text = C.ToString();
D = FourthNo.Next(0, 10);
TextD.Text = D.ToString();
Random FirstSign = new Random();
int x = FirstSign.Next(0, 2);
if(x == 0)
{
Sign1 = "+";
}
else if(x == 1)
{
Sign1 = "-";
}
TextSign1.Text = Sign1;
Random SecondSign = new Random();
int y = SecondSign.Next(0, 2);
if (y == 0)
{
Sign2 = "+";
}
else if (y == 1)
{
Sign2 = "-";
}
TextSign2.Text = Sign2;
}
You should have only one instance of Random, preferably for your entire program.
Random is automatically seeded with a time-based value when you create it using the default constructor:
Initializes a new instance of the Random class, using a time-dependent default seed value.
https://msdn.microsoft.com/en-us/library/h343ddh9(v=vs.110).aspx
The problem is, you are creating those four instances faster than the resolution of this time-based value. So all four instances are being seeded with the same value. And when called with the same parameters, each will return the same value.
Because of race conditions like this, you should keep just one global instance of Random if possible.
Use one instance and call .Next. Your issue is the seed for all of those Random instances is coming out the same (it defaults to a time-based seed).
The implementation is just an algorithm that requires a starting value to begin deriving other "random" values from. It isn't at all random, you can figure out what the value will be knowing the seed and the algorithm used.
Don't create a new Random instance every time.
Keep a single Random instance and call Next() for every new random number.
See this SO question for more details.

list of random objects from another list c# [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Select N random elements from a List<T> in C#
(34 answers)
Closed 8 years ago.
I have a list private List<HeroStats> allHeroes;
and a list private List<Team> allTeams;
After I populate my list 'allHeroes' with heroes , I want to create teams of 5 random heroes, using this method:
public Team createTeam()
{
int index=0;
Team t = new Team();
Random rnd = new Random();
int cap = allHeroes.Count;
while (t.count() < 5)
{
index = rnd.Next(0, cap);
t.Add(allHeroes.ElementAt(index));
}
return t;
}
This creates a perfect team , but if i want to create more teams, it will generate the same team over and over again.
I also have a method
public List<HeroStats> print()
{
StringBuilder sb = new StringBuilder();
List<HeroStats> l = new List<HeroStats>();
foreach (HeroStats h in team)
{
sb.AppendLine(h.HeroName);
l.Add(h);
}
Console.WriteLine(sb.ToString());
return l;
}
Which should print out the name of the heroes in a team.
Why am I getting the same team if I generate many ?
To create multiple teams I use :
Team a = new Team();
for (int i = 0; i < 2000; i++)
{
a = createTeam();
allTeams.Add(a);
}
It is creating the same teams because the Random instance is created in the method which is causing the same seed if you call createTeam very fast (the default Random constructor uses the current time as seed). You can avoid that either by passing the Random to the method or by using a field:
public Team createTeam(Random rnd) // as an aside, you should call it CreateRandomTeam
{
int index=0;
Team t = new Team();
int cap = allHeroes.Count;
while (t.count() < 5)
{
index = rnd.Next(0, cap);
t.Add(allHeroes.ElementAt(index));
}
return t;
}
Now you have to ensure that you pass always the same Random instance to createTeam.
For example with your loop:
Random rnd = new Random();
Team a = new Team();
for (int i = 0; i < 2000; i++)
{
a = createTeam(rnd);
allTeams.Add(a);
}
MSDN also mentions this in the remarks section:
The default seed value is derived from the system clock and has finite
resolution. As a result, different Random objects that are created in
close succession by a call to the default constructor will have
identical default seed values and, therefore, will produce identical
sets of random numbers. This problem can be avoided by using a single
Random object to generate all random numbers. You can also work around
it by modifying the seed value returned by the system clock and then
explicitly providing this new seed value to the Random(Int32)
constructor
You need to have
Random rnd = new Random();
Outside of
public Team createTeam()
{
}
Maybe parse in the rnd as a parameter.
From the documentation of Random
The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers.
If you are calling createTeam() in a tight loop to create your random teams, you will end up with the same set of random numbers due to the fact that your instances of Random are create so close to each other and with the same seed.
A possible solution is to take out the object of type Random and make it a class level field.
public static class RandomTeamCreator
{
private static readonly Random _random = new Random();
public Team CreateTeam()
{
// create team using _random
}
}
Why am I getting the same team if I generate many ?
Probably because the time between creating teams is not enough for the internal clock to create a new random seed.
I would add a "seed" parameter to createTeam:
public Team createTeam(int seed)
{
int index=0;
Team t = new Team();
Random rnd = new Random(seed);
int cap = allHeroes.Count;
while (t.count() < 5)
{
index = rnd.Next(0, cap);
t.Add(allHeroes.ElementAt(index));
}
return t;
}
And then use another Random outside of th eloop to generate the seed:
for(int 1 = 0; i < 10; i++)
{
Random r = new Random(0);
int seed = r.Next();
createTeam(int seed);
}
If you wanted to keep the original signature just add an overload:
public Team createTeam()
{
return createTeam(new Random().Next());
}
SIDE NOTE
You _probably want a "shuffled" team of heroes rather than a "random" since with "random" you could get the same hero twice. If that is the case then just use an "order by" with a random order:
public Team createTeam(int seed)
{
Random rnd = new Random(seed);
Team t = new Team();
var shuffled = allHeroes.OrderBy(rnd.Next()).Take(5);
foreach(var hero in shuffled)
t.Add(hero);
return t;
}
If you create many Random instances at roughly the same time, they are likely to generate the same numbers. Instead, create one Random somewhere else and call its Next method from your algorithm.

C# code only gives expected results on step through?

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);

Categories

Resources