Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Visual Basic Random Number not so Random? 1

Status
Not open for further replies.

BadbeatBurley

Programmer
Jun 27, 2019
6
US
I have written a small visual basic program that simulates a dice roll and tallies the results.
I seed the random number generator with the milliseconds value of time to start the program.
The results always have the number six come up less than the 16.66 percent than it should. Can someone explain why?
1000 T = 100000
1012 Dim Arrayz (2,7)
1200 ' Load array
1600 FOR N = 1 TO T
1612 Y = ((RND(1)*6) +1)
1620 Z = int(Y)
2000 Arrayz(1,Z) = Arrayz (1,Z) + 1
2010 next N
2040 ' load array for sorting
2050 For X = 1 to 6
2110 Arrayz(2,X) = X
2200 next X
2202 ' sort array
2250 C = 0
2300 For X = 1 to 5
2305 If Arrayz(1,X) > Arrayz(1,X+1) then
2310 Arrayz(1,7) = Arrayz(1,X)
2315 Arrayz(1,X) = Arrayz(1,X+1)
2320 Arrayz(1,X+1) = Arrayz(1,7)
2330 Arrayz(2,7) = Arrayz(2,X)
2333 Arrayz(2,X) = Arrayz(2,X+1)
2337 Arrayz(2,X+1) = Arrayz(2,7)
2339 C = 1
2340 else
2344 end if
2350 Next X
2360 IF C = 1 then goto 2250
2499 'unload and print
2500 For X = 1 to 6
2560 P = (Arrayz(1,X)/T)*100
2580 Pcnt6$ = using("##.####", P)
2590 Print "%",Pcnt6$ ," ", Arrayz(2,X)
2600 Next X
3002 end







 
Because

1612 Y = ((RND(1)*6) +1)
1620 Z = int(Y)

Has only one chance for Z=7 while there are many chances for 1 through 6.
 
Thanks for the reply, but not sure I understand how it has one chance for Z=7 ? The other numbers all come up with a 16.66 percent hit except for the number 6 which consistently runs low. Confused.
 
>I seed the random number generator with the milliseconds value of time to start the program.

Where?

The code as posted generates the same sequence of random numbers very time it is run - not that the code as posted will actually run, since this line

[tt]Pcnt6$ = using("##.####", P)[/tt]

won't work (because we don't know what 'using' is, and, if it is somehow a typo for Format, then the function parameters are wrong)

Also, this doesn't really seem to be Visual Basic, looks more like QBASIC or MSBasic code that happens to be able to run under VB thanks to a level of backwards compatibility.

The point is that since it would appear there are bits of code missing it is difficult to offer advice as to what may be happening.

Suffice it to say that "The other numbers all come up with a 16.66 percent" is an oddity. There should be some variation (indeed, the fact that you have a sort routine suggests that you expect there to be variation)

And if I run a pretty literal version of this in proper VB, it provides correct results, such as:

[tt][pre]% 16.5943 4
% 16.635 2
% 16.6701 1
% 16.6758 6
% 16.6919 5
% 16.7329 3[/pre][/tt]


So, to help us help you, can you please

a) Provide all the relevant code
b) Document what is really hosting and running your code (VB IDE, a VBA host, Scripting engine such as CSRIPT or WSCRIPT, something else …)
c) Provide some typical results output, that shows the problem you describe, similar to my example output above

 
BTW, the code I ran (under VBA hosted in Excel, as I don't have VB quickly at hand at work) to get my example results is as follows (as close as possible to your original code):

Code:
[blue]Public Sub Example()
    Randomize
    T = 1000000
    Dim Arrayz(2, 7)
    ' Load array
    For N = 1 To T
       Y = ((Rnd(1) * 6) + 1)
       Z = Int(Y)
       Arrayz(1, Z) = Arrayz(1, Z) + 1
    Next N
    ' load array for sorting
    For X = 1 To 6
       Arrayz(2, X) = X
    Next X
    ' sort array
2250      C = 0
    For X = 1 To 5
       If Arrayz(1, X) > Arrayz(1, X + 1) Then
          Arrayz(1, 7) = Arrayz(1, X)
          Arrayz(1, X) = Arrayz(1, X + 1)
          Arrayz(1, X + 1) = Arrayz(1, 7)
          Arrayz(2, 7) = Arrayz(2, X)
          Arrayz(2, X) = Arrayz(2, X + 1)
          Arrayz(2, X + 1) = Arrayz(2, 7)
          C = 1
       Else
       End If
    Next X
    If C = 1 Then GoTo 2250
    'unload and print
    For X = 1 To 6
    P = (Arrayz(1, X) / T) * 100
    Pcnt6$ = Format(P, "##.####")
    Debug.Print "%", Pcnt6$, " ", Arrayz(2, X)
    Next X
End Sub[/blue]
 
Simply put, this does not simulate a 6-sided die toss.

Because the T number of results will include some number of 7 that are not possible from a 6-sided die.

 
>will include some number of 7 that are not possible from a 6-sided die

I think you may be mistaken. Z never equals 7 with the code provided (Int is not the same as CInt)
 
Ah, OK.

[URL unfurl="true" said:
https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/rnd-function?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev11.query%3FappId%3DDev11IDEF1%26l%3Den-US%26k%3Dk(vblr6.chm1009008)%3Bk(TargetFrameworkMoniker-Office.Version%3Dv16)%26rd%3Dtrue[/URL]]The Rnd function returns a value less than 1 but greater than or equal to zero.

I had thought it returned 0 to 1 inclusive.

On other topic:

The 2D array and sorting seems to add no useful value to the function.

This
Code:
Option Base 1

Public Sub dietoss()
Dim myArray(6)
Dim NumTosses As Long
Dim TossValue As Integer
Dim Toss As Long
Dim Count As Integer

Randomize
NumTosses = 1000000

For Toss = 1 To NumTosses

    TossValue = (Int((Rnd(1) * 6) + 1))
    myArray(TossValue) = myArray(TossValue) + 1
    
Next Toss

For Count = 1 To 6
    Debug.Print (Count & " : " & myArray(Count) / NumTosses)
Next Count

End Sub

Returns
1 : 0.16712
2 : 0.166675
3 : 0.166614
4 : 0.166136
5 : 0.166082
6 : 0.167373

With a lot more simplicity.
 
OP wants the output in increasing order. But yes, if you remove the sorting requirement, then a load simpler.
 
OK, I agree with you and I still have the question...…. IF you take code from MintJulep and run a million tries several times, it will show the results are consistently low for the number 6 compared to the other numbers see attached screen capture. How can that be true if it is purely random? Why does Six come up short?

Num % % % %
1 0.168147 0.167891 0.167599 0.167525
2 0.167834 0.167765 0.167435 0.168692
3 0.166916 0.167547 0.166954 0.167226
4 0.166202 0.166134 0.166571 0.166651
5 0.165771 0.166323 0.166062 0.165155
6 0.165130 0.164340 0.165349 0.164892
 
 https://files.engineering.com/getfile.aspx?folder=dfe342de-53b4-41c8-ba56-67b612f3e5fb&file=Capture.JPG
> IF you take code from MintJulep and run a million tries several times

Well, no it doesn't. Or at least not here, on multiple different VBA platforms. And not for MintJulep either - as you can see from the result they provided in their post. There is clearly something else going on at your end. MintJulep's code specifically removes sorting - and yet your results are all seemingly sorted in descending order - apart, oddly, from one line in your 2nd set and one line in your 4th set - and therefore item 6 on the list will inevitably the lowest. And item 5 will always be the 5th lowest, and item 4 … (you get the drift)

Once again, what VB(A) platform are you running this on? I ask because the JPG you provided suggests (as I hypothesised earlier) that this isn't VB(A) at all.
The icon seems vaguely familiar, but I can't place it.


(note that if VB's PRNG, whilst not best of class in some respects, was this rubbish it would have been noticed way before now …)
 
Actually I was running Just BASIC v2.0 Copyright 1992-2018 Shoptalk Systems

The results I posted last time came from me running the MintJulep code with "no sort" in it. So as you can see, the percentage goes down from 1 to six. Here is the code. Can you explain why?

Dim myArray(6)
X=6
Randomize(X)
NumTosses = 1000000

For Toss = 1 To NumTosses

TossValue = (Int((Rnd(1) * 6) + 1))
myArray(TossValue) = myArray(TossValue) + 1

Next Toss

For Count = 1 To 6
Print Count, " : ", (myArray(Count) / NumTosses)
Next Count
 
Actually, here is the code for the values, as the last post didn't randomize with a variable.
Dim myArray(6)
R =TIME$("milliseconds")
F$ = STR$(R)
R = VAL(RIGHT$(F$,2))
RANDOMIZE (R)

NumTosses = 1000

For Toss = 1 To NumTosses

TossValue = (Int((Rnd(1) * 6) + 1))
myArray(TossValue) = myArray(TossValue) + 1

Next Toss

For Count = 1 To 6
Print Count, " : ", (myArray(Count) / NumTosses)
Next Count



 
Aha! Just BASIC. So nothing to do with VB, VBA or any related MS language.

Liberty BASIC, from which Just BASIC is derived, had a fairly notorious bias in its PRNG. I'd suggest what you are seeing is an artifact of that.

Nothing to do with VB or VB's PRNG, though.

In VB we don't see the problem you are describing.
 
Great catch strongm! Often we do all the hard work and write hundreds of lines of code and miss just one key thing i.e. Randomize (in this case). Liked you reply - well done!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top