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);
}
Related
This question already has answers here:
ArgumentOutOfRangeException on initialized List
(1 answer)
How to initialize a List<T> to a given size (as opposed to capacity)?
(16 answers)
Closed 4 years ago.
So I've been looking around for quite a while to try and find a solution to this.
I've been trying to make a card game and am stuck at a section in which I create a cad along with its properties. i decided to make it in the form of an array. The code looks like:
(not sure what happened with these first ones)
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>(Cards);
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
No errors are raised before I run the code but when I try it an Argument out of range exception occurs for the line: playerCards[0].Add(Int32.Parse(dogs[x]));
I tried removing it and the same error occured for the next line. I'm not sure what I've done wrong and have tried to find a solution for quite some time. If anyone has any tips or answers that would be great.
Thanks
try this :
string[] dogs = System.IO.File.ReadAllLines(#"C:\Users\corin\Documents\C# coding\dogs.txt");
int individual = totalCards / 2;
Random r = new Random();
int Cards = totalCards / 2;
List<List<int>> playerCards = new List<List<int>>();
//the missing piece
for (int i = 0; i < (Cards ); i++)
{
playerCards.add(new List<int>());
}
for (int x = 0; x < (Cards-2); x++)
{
playerCards[0].Add(Int32.Parse(dogs[x]));//Cards
playerCards[1].Add(r.Next(1, 6));//Drool
playerCards[2].Add(r.Next(1, 101));//Exercise
playerCards[3].Add(r.Next(1, 11));//Intelligence
playerCards[4].Add(r.Next(1, 11));//Friendliness
}
In addition to the previous answers: new List<List<int>>(Cards) doesn't do what you think it does. It sets capacity, not elementCount (or whatever it's called). When bounds are checked, elementCount is used, not capacity. capacity is useful when you have a good idea how many elements you have, to avoid reallocations and don't waste space.
So yes, before accessing by index you should add elements into the list manually.
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.
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.
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 8 years ago.
I am using Random to generate a sequence of random number. I am constructing the random object just once and then inside the loop generating the random values (300 of them). The problem is that once I get all the values and do a sort on them I realize that some of them are equal and/or sequential: I am generating numbers from 0 to 50000.
This is my script:
Random rnd = new Random();
for (int n=0; n < 300; n++)
{
int RndNumber = rnd.Next(0, 50000);
System.Threading.Thread.Sleep(3);
}
Can someone have a clue on why this is happening, and how can I improve this to make it more random?
So this is the birthday paradox*. When you draw 300 numbers from 50000 the approximate probability that at least two of them are equal is
p(300) = 1 - exp(-300 * 300 / (2 * 50000))
= 0.59
(I could work out the exact probability but I'm lazy!.)
So, chances are more likely than not that you'll have a collision. Sequential is even more likely (now you don't need a collision, you just need n - 1 and n or n and n + 1 to be hit for some n).
Random is fickle.
*: In case you're not familiar with it, it says that if you have twenty-three people in a room, it is more likely than not that at least two people in the room share the same birthday.
!: Okay, I worked it out. It's 0.5953830515549951746819986449....
Research:
If you use the constructor without parameters new Random() the seed is depending on the current servertime.
Random(): "Initializes a new instance of the Random class, using a time-dependent"
http://msdn.microsoft.com/en-us/library/system.random.aspx
So, if I try it like this:
for(int i = 0; i < 1000; i++)
{
Random ran = new Random();
Console.WriteLine(ran.Next(50001));
}
I only get 3 different numbers about 300 times within a thousand calls! Not that random...
Setting the seed in the constructor new Random(0) returns a fix serie of numbers.
e.g. new Random(0).Next(50) always! returns 36. Try it yourself, if you don't trust me;
What we need for "real" random numbers is a changing seed, that's independent of time.
I'm using Hashcode of changing values:
e.g. Guid.NewGuid().GetHashCode() or DateTime.Now.GetHashCode()
Result:
Random ran = new Random(Guid.NewGuid().GetHashCode());
for(int i = 0; i < 1000; i++)
{
Console.WriteLine(ran.Next(50001));
}
or (for better performance):
for(int i = 0; i < 1000; i++)
{
int val = Guid.NewGuid().GetHashCode() % 50001;
val = val > 0 ? val : -val;
Console.WriteLine(val);
}
PS: The maximum of the Next(max)-method is always max - 1;
-> ran.Next(11) can return 0,1,2,...,8,9,10. Not 11!
As an explanation of why you're seeing the occasional duplicate, Jason's answer is right on.
If what you want is 300 distinct random numbers, what about something like this?
static IEnumerable<int> GetRandoms(int min, int max)
{
var rand = new Random();
while (true)
{
yield return rand.Next(min, max);
}
}
var distinctRandoms = GetRandoms(0, 50000).Distinct().Take(300);
I want to generate 25 unique random numbers and list them in a console. The numbers should be atleast 10 characters long. Any easy way to do that?
Try building the numbers up as strings, and use a HashSet to ensure they are unique:
Random random = new Random();
HashSet<string> ids = new HashSet<string>();
while (ids.Count < 25)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; ++i)
{
sb.Append(random.Next(10));
}
ids.Add(sb.ToString());
}
Example output:
7895499338
2643703497
0126762624
8623017810
...etc...
The class HashSet is present in .NET 3.5 and newer.
The problem lies a little in "25 unique random". Displaying 25 random numbers is as easy as
Random r = new Random();
for(int i=0; i<25; i++)
Console.WriteLine(r.Next(1,100).ToString());
These are not necessarily unique, though. If you do not want to allow duplicates, you need to store previously generated numbers somehow, and roll again if you hit an old one.
Be aware that you change the probability distribution of your generated numbers this way.
Edit: I've just noticed that these numbers should be ten characters long. Since 9,999,999,999 exceeds Int32.MaxValue, I'd suggest using Math.Floor(r.NextDouble() * 10000000000 + 1000000000) instead of r.Next(1,100).
Since your numbers are that long, you should not need to worry about duplicates. They are very very unlikely.
There is a big different between Randomness and Uniqueness.
So if you need really unique numbers you have to make sure that you save somewhere all already created numbers and check if your newly created one isn't within this list or you have to provide some algorithm that ensures that a given number can't created twice.
To get the second part to work you mostly take the date/time of the creation moment, cause the current date/time pair is unique forever. The only problem is how many creations per (milli)second do you have and how many digits are available to store your unique number.
A sample about using 12 digits is made here. Hope this helps.
One simple way is this:
class Test
{
private static void Main()
{
Random rand = new Random();
for (int i = 0; i < 25; ++i)
{
Console.WriteLine(rand.Next(1000000000, int.MaxValue));
}
}
}
This will ensure that the numbers are always 10 characters (digits) long. They will not necessarily be unique however. If you want them to definitely be unique, you'll have to do something like this:
class Test
{
private static void Main()
{
Random rand = new Random();
var generatedSoFar = new HashSet<int>();
for (int i = 0; i < 25; ++i)
{
int newRand;
do
{
newRand = rand.Next(1000000000, int.MaxValue);
} while (generatedSoFar.Contains(newRand)); // generate a new random number until we get to one we haven't generated before
generatedSoFar.Add(newRand);
Console.WriteLine(newRand);
}
}
}
If you want to be able to have more than ten digits, you generate the number of digits randomly between 10 and your max number of digits. Then generate each digit (or group of digits) randomly in a StringBuilder or List. You can use the same HashSet method I used above to ensure uniqueness.
Random rnd = new Random(table);
for(int i = 0; i < 25; ++i) {
Console.WriteLine("{0}", rnd.Next(50, 50+i)
}