Answered by:
Random Number Not Random

Question
-
User-1546380551 posted
Hi,
VB.NET 2012 using Framework 4.5
I am trying to get 3 random numbers which works fine within a Windows app but not in a Web app.
Protected Function GetNextPhoto(intMaxPics As Integer) As Integer Dim rnd As New Random Dim intRandom As Integer intRandom = rnd.Next(1, intMaxPics) Return intRandom End Function
or
Private Function GetAnotherNumber(i As Integer) As Integer Dim r As New Random Dim ii As Integer = r.Next(i) Return ii End Function
If I do:Dim intPic As Integer = GetAnotherNumber(22)
I get the first random number - great.
If I then do:
intPic = 0 intPic = GetAnotherNumber(22)
to generate another random number I get the same number I originally had. The same thing happens for all three so it's not random. If I refresh the page the same number is again returned 3 times, and so on.
Any ideas how I can resolve this?
Thanks
Sunday, August 25, 2013 3:33 PM
Answers
-
User2103319870 posted
Hi,
Move the declaration of the random number generator out of the loop.
Please try to modify your method like given below
Private Shared ReadOnly r As New Random() Public Function GetAnotherNumber(i As Integer) As Integer Dim ii As Integer = r.[Next](i) Return ii End Function
Refer this link for more details
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, August 25, 2013 3:39 PM -
User-760709272 posted
Random works off of a "seed" which is a random number sequence based on using that seed with an equation. So if you create Random(1) and ask for 5 numers you'll always get the same sequence. If you fo Random(10) you'll also get the same sequence every time, though a different sequence from Random(5).
Just Random on its own uses a time-based seed, so if you create new copies of Random very quickly they'll have the same seed so give the same answers. If you need 3 numbers and create new Random for each number you'll get the same 3 numbers. What you have to do is create just one instance of Random, and use that same instance to get the next 3 numbers.
So, basically, GetAnotherNumber when called in quick succession will usually give the same number each time as it is using the same seed. If you want three numbers then add a parameter to your function that says how many numbers you want, and make your function return a List<int> of three numbers using the same instance of Random.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, August 25, 2013 3:41 PM -
User753101303 posted
Hi,
Use a single Random object rather than creating a new one each time. If you create them too quickly you actually create 3 times the same sequence (as generated values are time dependent) and just consume the first value (which will be the same for all 3 sequences).
Instead, if you create a single Random object, you'll create a single sequence of random numbers and will consume the first 3 values which will be all different...
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, August 25, 2013 3:43 PM
All replies
-
User2103319870 posted
Hi,
Move the declaration of the random number generator out of the loop.
Please try to modify your method like given below
Private Shared ReadOnly r As New Random() Public Function GetAnotherNumber(i As Integer) As Integer Dim ii As Integer = r.[Next](i) Return ii End Function
Refer this link for more details
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, August 25, 2013 3:39 PM -
User-760709272 posted
Random works off of a "seed" which is a random number sequence based on using that seed with an equation. So if you create Random(1) and ask for 5 numers you'll always get the same sequence. If you fo Random(10) you'll also get the same sequence every time, though a different sequence from Random(5).
Just Random on its own uses a time-based seed, so if you create new copies of Random very quickly they'll have the same seed so give the same answers. If you need 3 numbers and create new Random for each number you'll get the same 3 numbers. What you have to do is create just one instance of Random, and use that same instance to get the next 3 numbers.
So, basically, GetAnotherNumber when called in quick succession will usually give the same number each time as it is using the same seed. If you want three numbers then add a parameter to your function that says how many numbers you want, and make your function return a List<int> of three numbers using the same instance of Random.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, August 25, 2013 3:41 PM -
User753101303 posted
Hi,
Use a single Random object rather than creating a new one each time. If you create them too quickly you actually create 3 times the same sequence (as generated values are time dependent) and just consume the first value (which will be the same for all 3 sequences).
Instead, if you create a single Random object, you'll create a single sequence of random numbers and will consume the first 3 values which will be all different...
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, August 25, 2013 3:43 PM -
User-183374066 posted
You need to use SyncLock to stop this repeating behaviour ..
Public Shared Function GetRandomNumber(minValue As Integer, maxValue As Integer) As Integer SyncLock synchLock Thread.Sleep(100) Return random.[Next](minValue, maxValue) End SyncLock End Function
http://revenmerchantservices.com/post/C-Generate-Random-Number.aspx
AidyF
There is no need to sleep for this to work. All you're doing is massively increasing your resources and decreasing the scalability of your site. Your whole page should take about 50ms or less to process, and if you want 5 random numbers your page is going to take 500ms minimum. Now imaging 1,000 people are browsing your site.Above is just an example.. Obviously he wouldn't use thread sleep on his page. :)
Note:If you are going to create more than one random number, you should keep the Random instance and reuse it. If you create new instances too close in time, they will produce the same series of random numbers as the random generator is seeded from the system clock.
http://stackoverflow.com/questions/2706500/how-to-generate-random-int-number-c
Sunday, August 25, 2013 3:46 PM -
User-1546380551 posted
Many thanks for all your replies. From such a simple post I have learnt a lot - thank you all
I found when I used the synchlock example there were more chances of getting 2 of the same number and was thinking that the random function was truly random but it is possible to predict the outcome as one reply basically mentioned.
What I will do now is play around with the synchlock code for numbers from 1 - 21, 000 and use the code where one reply moved the 'New Random' outside the function for the smaller numbers
Never knew about synchlock as I have been out of coding around 6 years so will look into that on MSDN more because that could resolve another issue I was experiencing in another class and never went back to - fingers crossed
Thank you once again for all the replies, advice, code & help
Sunday, August 25, 2013 4:10 PM -
User-760709272 posted
You need to use SyncLock to stop this repeating behaviour ..
Public Shared Function GetRandomNumber(minValue As Integer, maxValue As Integer) As Integer SyncLock synchLock Thread.Sleep(100) Return random.[Next](minValue, maxValue) End SyncLock End Function
http://revenmerchantservices.com/post/C-Generate-Random-Number.aspx
There is no need to sleep for this to work. All you're doing is massively increasing your resources and decreasing the scalability of your site. Your whole page should take about 50ms or less to process, and if you want 5 random numbers your page is going to take 500ms minimum. Now imaging 1,000 people are browsing your site.
Sunday, August 25, 2013 4:36 PM -
User753101303 posted
In my opinion this is really a bad way to solve the problem. It doesn't solve the real issue but instead it adds some code to counter its effect.
Once again the real problem is that you create 3 times the same sequence of random numbers and consuming only the first value which is always the same (because they are initialized based on the time and you care creating them in close succession you end up 3 times with the same series of random numbers).
Instead you should create a single sequence of random numbers and consume 3 values from this sequence. See :
Random r; // Bad for(int i=1;i<=3;i++) { r=new Random(); // Same sequence System.Diagnostics.Debug.WriteLine(r.Next(100)); // First value } // Good r=new Random(); // Single sequence for(int i=1;i<=3;i++) { System.Diagnostics.Debug.WriteLine(r.Next(100)); // First, second, third value of a single sequence }
Values are shown in the debugger output window...
(Sorry I'm using both VB and C# and realized you are using VB, this is the same problem anyway ie. creating 3 sequences in close succession and using the first value, rather than creating a single sequence and consuming the first 3 values).
Sunday, August 25, 2013 4:55 PM -
User-1546380551 posted
Hi,
I understand your point but when I tested it with numbers 1 - 20 (GetRandomNumber(1, 20)), 3 of the 4 times two numbers were the same compared to 1 in 7'ish without synchlock. Maybe when I scale it up the possibilities are going to be far less like with the lottery.
You make a very good point about not making the thread sleep and that noticeable difference would be picked-up with Googlebot too. Although, I remember that you shouldn't use Thread.Sleep in a web app but use a different method of sleeping the thread (same thing but a different way for web apps). Not to worry, as it wouldn't be used given your argument of page speed.
Sunday, August 25, 2013 4:56 PM -
User-760709272 posted
It's not the lock that is doing it, it's the sleep that is ensuring each time random is created that it has a different seed. You should just generate the numbers you need in one go;
protected void Page_Load(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine(string.Join(",", GetRandomNumber(10, 3))); } public IEnumerable<int> GetRandomNumber(int max, int count) { Random r = new Random(); for (int i = 0; i < count; i++) { yield return r.Next(max); } }
Or if you need to do it right after another, don't use the time-based seed.
protected void Page_Load(object sender, EventArgs e) { int? last = null; for (int i = 0; i < 5; i++) { last = GetRandomNumber(10, last); System.Diagnostics.Debug.WriteLine(last); } } public int GetRandomNumber(int max, int? seed = null) { Random r = seed.HasValue ? new Random(seed.Value) : new Random(); return r.Next(max); }
Sunday, August 25, 2013 7:46 PM