Answered by:
Just curious about this Rnd(Rnd(Rnd*200)) result...

Question
-
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 yEnd Sub
End Module[Visual Basic 2008 vista SP1]
Thursday, January 6, 2011 1:50 PM
Answers
-
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
- Marked as answer by marine-tex Friday, January 7, 2011 8:49 PM
- Edited by JohnWein Friday, January 7, 2011 8:54 PM
Friday, January 7, 2011 8:45 PM
All replies
-
The largest rnd ever returns is 0.9999999
which happens every 1 to 6 million times or so0.9999999 cubed is 0.9999997
0.9999997 times 200 is 199.99994
The largest value that rnd*(rnd*(rnd*200)) ever returns is 198.3898Why?
Thursday, January 6, 2011 2:29 PM -
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?
--
AndrewThursday, January 6, 2011 2:50 PM -
If you want more predictable randoms use the .NET Random.Thursday, January 6, 2011 3:13 PM
-
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.Friday, January 7, 2011 4:24 PM -
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.Friday, January 7, 2011 4:46 PM
-
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 WhiteleyFriday, January 7, 2011 6:32 PM -
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
Friday, January 7, 2011 7:27 PM -
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.Friday, January 7, 2011 7:37 PM -
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- Edited by Andrew Morton Friday, January 7, 2011 7:51 PM Looked at wrong version of random.
Friday, January 7, 2011 7:42 PM -
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.
Friday, January 7, 2011 7:43 PM -
I do not know the algorithm, however, and I realize the algorithm may be the answer.
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.
I was just thinking someone knew more about the algorithm or whatever is causing this limitation.Friday, January 7, 2011 7:56 PM -
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
- Marked as answer by marine-tex Friday, January 7, 2011 8:49 PM
- Edited by JohnWein Friday, January 7, 2011 8:54 PM
Friday, January 7, 2011 8:45 PM -
Thanks so much, John. Your programs will keep me occupied for a while!Friday, January 7, 2011 8:53 PM
-
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()!
- Edited by marine-tex Friday, November 27, 2020 4:21 AM Typos!
Friday, November 27, 2020 4:04 AM