locked
Random Number Not Random RRS feed

  • 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