LuckySam said:
Dear Forum,
I am working on some new home-brew software.
I have already written the part that can generate a full wheel for any number of balls, any number to play. If it helps to know, the combinations come out in numerical order, e.g. for 5c3:
1) 123
2) 124
3) 125
4) 134
5) 135
...
10) 345
Now I am trying to figure out how to select N tickets from the full wheel, with the requirement that all balls appear with uniform frequency (if possible), or as close as possible (+/-1 from the mean).
My ideal algorithm would work in a loop, e.g.
for n=1:N
Pick the index of the next correct combination, 1-10, from the list above
end
But I don't know if that's possible -- I think probably not.
The algorithm would need to be a general one, not specific to a certain number of balls, so I prefer it to be calculated, rather than table-based for that reason.
Can anyone please direct me to a reference book that would explain such an algorithm? If necessary I can handle the math, but being an engineer I would prefer a cookbook
I appreciate your help,
Sam
Special cases may require special non-equidistant but stepwise constant distributions. These could be created with this function rww().
Function rww(ParamArray w() As Variant) As Double
'Produces random numbers with defined widths & weights
'06/08/2004 by Bernd Plumhoff. rww expects a vector of n random widths and
'weightings of type double and returns a random number of type double. 'This random number will lie in the given n-width-range of the
'(0,1)-intervall with the given likelihood of the n weightings.
'Examples:
'a) rww(1,0,1,1,8,0) will return a random number between 0.1 and 0.2
'b) rww(5,2,5,1) will return a random number between 0 and 0.5 twice as
' often as a random number between 0.5 and 1.
'c) rww(1/3,0,1/3,1,1/3,0) will return a random number between
' 0.33333333333333 and 0.66666666666666.
'd) rww(5,15.4,3,7.7,2,0) would return a random value between
' 0 and 0.8, first 5 deciles with double likelihood than decile 6-8.
Dim i As Integer
Dim swidths As Double
Dim sw As Double
If (UBound(w) + 1) Mod 2 <> 0 Then
rww = -2 'No even number of arguments: Error
Exit Function
End If
ReDim swidthsi(0 To (UBound(w) + 1) / 2 + 1) As Double
ReDim swi(0 To (UBound(w) + 1) / 2 + 1) As Double
ReDim weights(0 To (UBound(w) + 1) / 2) As Double
ReDim widths(0 To (UBound(w) + 1) / 2) As Double
swidths = 0#
sw = 0#
swi(0) = 0#
swidthsi(0) = 0#
For i = 0 To (UBound(w) - 1) / 2
If w(2 * i) < 0# Then 'A negative width is an error
rww = -3#
Exit Function
End If
widths(i) = w(2 * i)
swidths = swidths + widths(i)
swidthsi(i + 1) = swidths
If w(2 * i + 1) < 0# Then 'A negative weight is an error
rww = -1#
Exit Function
End If
weights(i) = w(2 * i + 1)
If widths(i) > 0# Then
sw = sw + weights(i)
End If
swi(i + 1) = sw
Next i
rww = sw * Rnd
i = (UBound(w) - 1) / 2 + 1 'i already equals (UBound(w) - 1) /
'2 + 1, you may omit this statement.
While rww < swi(i)
i = i - 1
Wend
rww = (swidthsi(i) + (rww - swi(i)) / weights(i) * widths(i)) / swidths
End Function
Suppose you want to simulate teachers who judge pupils. Some teachers do not dare to give extreme grades (assume they give grade 1 for 2% of all cases, grade 2 for 8%, grade 3 for 80%, grade 4 for 8% and grade 5 for 2%). The next teacher is too critical, his distribution is 40%, 30%, 20%, 10% and 0% for grades 1 till 5. Another one only gives grade 4 (60%) and grade 5 (40%). A last one finally offers a “fair” normal distribution (10%, 20%, 40%, 20%, 10%).
How do you produce these random numbers which are distributed as mentioned above? Take the following procedure redw() which creates random numbers with equidistant weights. This function would be called with =INT(1+5*redw(10,20,40,20,10)) to simulate the “fair” teacher, for example.
Option Explicit
Function redw(ParamArray w() As Variant) As Double
' Produces random numbers with equidistant weights
' 06/08/2004 by sulprobil. redw expects a vector of n random
' weightings of type double and returns a random number of type double. This random
' number will lie in the given equidistant n-split-range of the (0,1)-intervall
' with the given likelihood of weightings. Examples:
' a) redw(0,1,0,0,0,0,0,0,0,0) will return a random number between 0.1 and 0.2
' b) redw(2,1) will return a random number between 0 and 0.5 twice as
' often as a random number between 0.5 and 1.
' c) redw(0,1,0) will return a random number between 0.33333333333333 and 0.66666666666666.
' d) redw(15.4,15.4,15.4,15.4,15.4,7.7,7.7,7.7,0,0) would return a random value between
' 0 and 0.8, first 5 deciles with double likelihood than decile 6-8.
Dim i As Integer
Dim sw As Double
ReDim swi(0 To UBound(w) + 2) As Double
sw = 0#
swi(0) = 0#
For i = 0 To UBound(w)
If w(i) < 0# Then 'A negative weight is an error
redw = -1#
Exit Function
End If
sw = sw + w(i) 'Calculate sum of all weights
swi(i + 1) = sw 'Calculate sum of weights till i
Next i
redw = sw * Rnd
i = UBound(w) + 1 ' i already equals UBound(w) + 1, you may omit this statement.
While redw < swi(i)
i = i - 1
Wend
redw = (CDbl(i) + (redw - swi(i)) / w(i)) / (CDbl(UBound(w) + 1))
End Function
Function rand_triang(dMin As Double, dMode As Double, _
dMax As Double) As Double
'Generates a random number, Triang distributed
'[see Vose: Risk Analysis, 2nd ed., p. 128]
'Reverse(moc.LiborPlus.www) 03-May-2007 V0.1
'Similar to @RISK's (C) RiskTriang function.
'rand_triang(minimum,mode,maximum) specifies a triangular
'distribution with three points — a minimum, a mode and
'a maximum. The skew of the triangular distribution is
'driven by the distance of the mode from the minimum and
'from the maximum. Reducing the distance from mode to
'minimum will increase the skew.
Dim dTriangInvMid As Double
Dim dRand As Double, dc_a As Double, db_a As Double
Dim dc_b As Double
Application.Volatile
If dMode <= dMin Or dMax <= dMode Then
rand_triang = CVErr(xlErrNum)
Exit Function
End If
dc_a = dMax - dMin
db_a = dMode - dMin
dc_b = dMax - dMode
'Calculate mid point of value range for cumulative inverse
'function
dTriangInvMid = db_a / dc_a
dRand = Rnd()
If dRand < dTriangInvMid Then
rand_triang = dMin + Sqr(dRand * db_a * dc_a)
Else
rand_triang = dMax - Sqr((1# - dRand) * dc_a * dc_b)
End If
End Function