locked
Just curious about this Rnd(Rnd(Rnd*200)) result... RRS feed

  • Pergunta

  • It seems to me that the following stmt
        r=rnd*(rnd*(rnd*200))
    ought to return a value over 199 occasionally (about 1 in 8 million times or so).  However, I've run this stmt in the following program, and in over 25,600,000,000 tries it has never reported a value over 199.   (However, 198 occurs regularly.)

    What am I missing here?

    option explicit off
    Module mainModule
    Sub Main()
    randomize()

    for y=1 to 1000000
      for x = 1 to 8000000 : R=rnd*(rnd*(rnd*200))
      if r>199 then console.writeline("  ! 199 !  ") '  Report if value is over 199
      next x
    console.write(Cstr(y)+" ") ' Report every 8 million tries
    next y

    End Sub
    End Module

    [Visual Basic 2008    vista SP1]

    quinta-feira, 6 de janeiro de 2011 13:50

Respostas

  • Until this thread, although I didn't use it, I thought that Rnd() was just as good as Random().  It isn't.  The following code repeats every 17,000,000 tests.  Making the commented changes to use Random(), I haven't found a repeat.

    Module Module1
      
    Sub Main()
        Console.WriteLine(
    "Running Test")
        
    Dim TestNo As Long
        'Dim Rnd as new Random
        Do
          TestNo += 1
          
    Dim Result As Double = Rnd() * 200  'Rnd.NextDouble
          If Result > 199 Then
            Dim Result2 As Double = Rnd() * 200 'Rnd.NextDouble
            If Result2 > 199 Then
              Dim result3 As Double = Rnd() * 200 'Rnd.NextDouble
              If result3 > 199 Then
                Console.WriteLine(TestNo.ToString + " " + Result.ToString + " " + Result2.ToString + " " + result3.ToString)
                TestNo = 0
              
    End If
            End If
          End If
        Loop
      End Sub
    End
     Module

    • Marcado como Resposta marine-tex sexta-feira, 7 de janeiro de 2011 20:49
    • Editado JohnWein sexta-feira, 7 de janeiro de 2011 20:54
    sexta-feira, 7 de janeiro de 2011 20:45

Todas as Respostas

  • The largest rnd ever returns is 0.9999999
    which happens every 1 to 6 million times or so

    0.9999999 cubed is 0.9999997

    0.9999997 times 200 is 199.99994


    The largest value that  rnd*(rnd*(rnd*200))  ever returns is 198.3898

    Why?

    quinta-feira, 6 de janeiro de 2011 14:29
  • You're assuming that the value returned by three consecutive invocations of rnd could be 0.9999999 each time. Perhaps a bit unlikely...

    Do use actually want to call rnd once and cube that?

    --
    Andrew

    quinta-feira, 6 de janeiro de 2011 14:50
  • If you want more predictable randoms use the .NET Random.
    quinta-feira, 6 de janeiro de 2011 15:13

  • Three .9999999s in a row aren't necessary; just close to it:

    If there were three values of 0.9983308 or greater in a row,
    the result of them cubed (0.9950007+) times 200 would be 199.0001+
       but it never happens in this program. 

    In billions of iterations, the result was always a max of 198.3898

    I don't need this resolved, I'm just curious what's going on.

     

    RE. JohnWein's suggestion:
    I don't know .NET  -  I barely know visual Basic! 
    I've used gwBasic my whole life - which vista 64bit won't run.

     

     

    sexta-feira, 7 de janeiro de 2011 16:24
  • Your rnds aren't independent.  As you've seen it's not possible for the pseudorandom rnd to generate the same number 3 times in succession.  If you used 3 .NET Randoms and ensured that they were seeded from widely different seeds, you might get the result you're looking for.
    sexta-feira, 7 de janeiro de 2011 16:46
  • I would also add that you possibly don't fully understand how 'random' (and probability) really works.

    I would ask why do you think it should return a value of X in Y iterations?

    Or asking another way, how many iterations would you need to have a 100% chance of getting the result you want at least once? How about a 95% chance of getting the result you want?

    What would you say if I got it on the first try?

    As a follow up, try thinking about probabilities from the position of NOT getting the result you want: that is, if there's a 1% chance of a given result, each time you try there's a 99% chance of NOT getting that result. In addition, each result is not dependent on the last result. If you rolled 6 dice in a row and each one rolled a 6, what is the chance of rolling another 6?

    (This is all aside from the fact that there's a difference between a random result and a computer generated pseudo-random result).


    Stephen J Whiteley
    sexta-feira, 7 de janeiro de 2011 18:32
  • Try this:

    Module Module1
      
    Sub Main()
        
    Dim Rnd(2) As Random
        Rnd(0) = 
    New Random
        Console.WriteLine(
    "Enter to seed Rnd(1)")
        Console.ReadLine()
        Rnd(1) = 
    New Random
        Console.WriteLine(
    "Enter to seed Rnd(2)")
        Console.ReadLine()
        Rnd(2) = 
    New Random
        Console.WriteLine(
    "Running Test")
        
    Dim TestNo As Long
        Do
          TestNo += 1
          
    Dim Result As Double = Rnd(2).NextDouble * Rnd(1).NextDouble * Rnd(0).NextDouble * 200
          
    If Result > 199 Then
            Console.WriteLine(TestNo.ToString + " " + Result.ToString)
            Console.WriteLine(
    "Enter Q to quit.")
            
    If Console.ReadLine = "Q" Then Exit Do
          End If
        Loop
      End Sub
    End
     Module
    Module
     Module1
      
    Sub Main()
        
    Dim Rnd(2) As Random
        Rnd(0) = 
    New Random
        Console.WriteLine(
    "Enter to seed Rnd(1)")
        Console.ReadLine()
        Rnd(1) = 
    New Random
        Console.WriteLine(
    "Enter to seed Rnd(2)")
        Console.ReadLine()
        Rnd(2) = 
    New Random
        Console.WriteLine(
    "Running Test")
        
    Dim TestNo As Long
        Do
          TestNo += 1
          
    Dim Result As Double = Rnd(2).NextDouble * Rnd(1).NextDouble * Rnd(0).NextDouble * 200
          
    If Result > 199 Then
            Console.WriteLine(TestNo.ToString + " " + Result.ToString)
            Console.WriteLine(
    "Enter Q to quit.")
            
    If Console.ReadLine = "Q" Then Exit Do
          End If
        Loop
      End Sub
    End
     Module

    sexta-feira, 7 de janeiro de 2011 19:27
  • I'm sure I have a good understanding of probabilities.  I also understand that the Rnd function in vBasic is a simulation of a random number, and is not random at all after the seed is established.

    I do not know the algorithm, however, and I realize the algorithm may be the answer.
    I was just thinking someone knew more about the algorithm or whatever is causing this limitation.


    To answer your question, I would NEVER have a 100% chance of getting the result I'm looking for.
    But if I have a 99.9999999% chance of getting said result, and I don't...   I consider that conclusive.

    sexta-feira, 7 de janeiro de 2011 19:37
  • I'm sure I have a good understanding of probabilities.  I also understand that the Rnd function in vBasic is a simulation of a random number, and is not random at all after the seed is established.

    I do not know the algorithm, however, and I realize the algorithm may be the answer.
    I was just thinking someone knew more about the algorithm or whatever is causing this limitation.

    From the help for Random,

    "The current implementation of the Random class is based on Donald E. Knuth's subtractive random number generator algorithm. For more information, see D. E. Knuth. "The Art of Computer Programming, volume 2: Seminumerical Algorithms". Addison-Wesley, Reading, MA, second edition, 1981."

    Edit: But that's for the .NET random, I couldn't quickly find a reference to how the VB random function works.

    --
    Andrew

    • Editado Andrew Morton sexta-feira, 7 de janeiro de 2011 19:51 Looked at wrong version of random.
    sexta-feira, 7 de janeiro de 2011 19:42
  • Thank you, John  —  I will try that.  I'm very short on sleep at the moment, and there are a couple things in your program I'm not familiar with, but I will learn them.

    sexta-feira, 7 de janeiro de 2011 19:43
  • I do not know the algorithm, however, and I realize the algorithm may be the answer.
    I was just thinking someone knew more about the algorithm or whatever is causing this limitation.
    You don't need to know the algorithm to know the limitation.  A pseudorandom number generator generates a finite predetermined sequence of numbers dependent upon the seed.  You're using 3 sequential numbers in that sequence.  Although each number generated by the generator obeys general criteria for randomess, sequential numbers are not random at all.  They are, in fact, deterministic.
    sexta-feira, 7 de janeiro de 2011 19:56
  • Until this thread, although I didn't use it, I thought that Rnd() was just as good as Random().  It isn't.  The following code repeats every 17,000,000 tests.  Making the commented changes to use Random(), I haven't found a repeat.

    Module Module1
      
    Sub Main()
        Console.WriteLine(
    "Running Test")
        
    Dim TestNo As Long
        'Dim Rnd as new Random
        Do
          TestNo += 1
          
    Dim Result As Double = Rnd() * 200  'Rnd.NextDouble
          If Result > 199 Then
            Dim Result2 As Double = Rnd() * 200 'Rnd.NextDouble
            If Result2 > 199 Then
              Dim result3 As Double = Rnd() * 200 'Rnd.NextDouble
              If result3 > 199 Then
                Console.WriteLine(TestNo.ToString + " " + Result.ToString + " " + Result2.ToString + " " + result3.ToString)
                TestNo = 0
              
    End If
            End If
          End If
        Loop
      End Sub
    End
     Module

    • Marcado como Resposta marine-tex sexta-feira, 7 de janeiro de 2011 20:49
    • Editado JohnWein sexta-feira, 7 de janeiro de 2011 20:54
    sexta-feira, 7 de janeiro de 2011 20:45
  • Thanks so much, John.  Your programs will keep me occupied for a while!
    sexta-feira, 7 de janeiro de 2011 20:53
  • For those who may be interested, Rnd() repeats its sequence (for a given seed) every 16777216 calls.

    So this code
        randomize(1234)
        do
           for x as single = 1 to 16777215 : rnd : next
           console.writeline(rnd.tostring)
        loop
    will write the same number over and over.


    More useless information...
    If you use rnd and then later want to get the same results you would've gotten if you had not used rnd, you gotta call rnd exactly as many times as will bring the total of rnd calls (so far) to 16777216 times - then randomize(seed) and continue as usual.
    If the two sequences you seek use the same seed, you do not need to repeat the randomize() cmd.

    Alternatively...
    If your pgrm is such that you may or may not have called rnd earlier, and you want to get the same results you would've gotten before you called rnd, you can use this code:
            z=rnd(-1)  :  randomize(seed)  :  for x=1 to 12827730  :  z=rnd  :  next
    '  Vb.net/net 2.0 should be re-initialized for rnd use     (z, x are type single)

    But don't use rnd() for security/encryption purposes!

    Use md5.computeHash(string) or Random.NextDouble or CryptoStream() or anything but Rnd()!


    • Editado marine-tex sexta-feira, 27 de novembro de 2020 04:21 Typos!
    sexta-feira, 27 de novembro de 2020 04:04