deming
asked on
Random Number Generator for PHP and VB6 (PRNG)
I need to be able to provide a seed to a pseudo random number generator (PRNG) in both VB6 and PHP (Linux) and have the results be identical. Thus I cannot use the built in VB6 random function because PHP does not use the same PRNG algorithm. Thus the same seed in VB6 does not generate the same sequence as in PHP.
Previously EE "htamas" suggested the below, however, it is not working when I do the following:
Bnd(-67)
Bandomize(67)
a=bnd()
rnd(-67)
Randomize(67)
b=rnd()
If a<>b then debug.print "ERROR: Sequence is not the same"
*** QUESTION: ***
Can anyone see what is wrong in htamas code below?
EE "htamas" solution which is close but not working:
-------------------------- ---------- ---------- ---------- ------
Here is the 'source code' for the VB6 built-in Random and Randomize functions. Not the actual source, but one that's identical to it:
Dim Lastband As Long
Sub Initbandom() 'This is run on startup
Lastband = &H50000
End Sub
Sub Bandomize(Optional Number)
Dim seed As Long
Dim cnum As Single
Dim bits As Long
Dim mask As Long
Dim i As Integer
If IIf(IsError(Number), 1, Number) = 0 Then
seed = 0
Else
cnum = IIf(IsError(Number), Timer, Number)
seed = &H4130
Do While cnum >= 2097152
cnum = cnum / 2
seed = seed + &H10
Loop
Do While cnum < 1048576
cnum = cnum * 2
seed = seed - &H10
Loop
bits = Int(cnum)
mask = 1
For i = 1 To 20
If bits And 1 Then
seed = seed Xor mask
End If
bits = bits \ 2
mask = mask * 2
If i = 16 Then mask = 1
Next i
End If
Lastband = seed * &H100 + Lastband Mod &H100
End Sub
Function Bnd(Optional Number) As Single
Dim p As Long, q As Long, j As Long
If IIf(IsError(Number), 1, Number) > 0 Then
p = Lastband
q = &HFD43FD
d = &HC39EC3
For j = 1 To 6
d = (d + (p Mod &H10) * q) Mod &H1000000
p = p \ &H10
q = (q * &H10) Mod &H1000000
Next j
Lastband = d
ElseIf Number < 0 Then
Lastband = &H395886
End If
Bnd = CSng(Lastband) / &H1000000
End Function
Previously EE "htamas" suggested the below, however, it is not working when I do the following:
Bnd(-67)
Bandomize(67)
a=bnd()
rnd(-67)
Randomize(67)
b=rnd()
If a<>b then debug.print "ERROR: Sequence is not the same"
*** QUESTION: ***
Can anyone see what is wrong in htamas code below?
EE "htamas" solution which is close but not working:
--------------------------
Here is the 'source code' for the VB6 built-in Random and Randomize functions. Not the actual source, but one that's identical to it:
Dim Lastband As Long
Sub Initbandom() 'This is run on startup
Lastband = &H50000
End Sub
Sub Bandomize(Optional Number)
Dim seed As Long
Dim cnum As Single
Dim bits As Long
Dim mask As Long
Dim i As Integer
If IIf(IsError(Number), 1, Number) = 0 Then
seed = 0
Else
cnum = IIf(IsError(Number), Timer, Number)
seed = &H4130
Do While cnum >= 2097152
cnum = cnum / 2
seed = seed + &H10
Loop
Do While cnum < 1048576
cnum = cnum * 2
seed = seed - &H10
Loop
bits = Int(cnum)
mask = 1
For i = 1 To 20
If bits And 1 Then
seed = seed Xor mask
End If
bits = bits \ 2
mask = mask * 2
If i = 16 Then mask = 1
Next i
End If
Lastband = seed * &H100 + Lastband Mod &H100
End Sub
Function Bnd(Optional Number) As Single
Dim p As Long, q As Long, j As Long
If IIf(IsError(Number), 1, Number) > 0 Then
p = Lastband
q = &HFD43FD
d = &HC39EC3
For j = 1 To 6
d = (d + (p Mod &H10) * q) Mod &H1000000
p = p \ &H10
q = (q * &H10) Mod &H1000000
Next j
Lastband = d
ElseIf Number < 0 Then
Lastband = &H395886
End If
Bnd = CSng(Lastband) / &H1000000
End Function
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Hehe, some words about "RANDOM" M$ algorithm :)
Private Sub Command1_Click()
Randomize Timer
Debug.Print "=================="
Debug.Print "And now, how [random] it is:"
Debug.Print "Using a=2^24*Rnd And 3"
Debug.Print "=================="
For i = 1 To 100
a = 2 ^ 24 * Rnd And 3
Debug.Print a & ", ";
Next i
End Sub
'Output:
3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0
Seems VERY (!) {random} :)))))
Private Sub Command1_Click()
Randomize Timer
Debug.Print "=================="
Debug.Print "And now, how [random] it is:"
Debug.Print "Using a=2^24*Rnd And 3"
Debug.Print "=================="
For i = 1 To 100
a = 2 ^ 24 * Rnd And 3
Debug.Print a & ", ";
Next i
End Sub
'Output:
3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0
Seems VERY (!) {random} :)))))
BTW, just courious, why do you need PHP script code if you already have VB one? Just create ActiveX dll, smth like
Public Sub DoRandomize(Optional val)
Randomize val
End Sub
Public Function DoRnd(optional val)
DoRnd = Rnd(val)
End Function
And then, in PHP
$o = New COM("YourRndClassName");
$o->DoRandomize();
echo $o->DoRnd();
PS
To much more secure random sequense, you can use
Private Declare Function CryptGenRandom Lib "advapi32.dll" _
(ByVal hProv As Long, ByVal dwLen As Long, ByVal pbBuffer As String) As Long
Public Sub DoRandomize(Optional val)
Randomize val
End Sub
Public Function DoRnd(optional val)
DoRnd = Rnd(val)
End Function
And then, in PHP
$o = New COM("YourRndClassName");
$o->DoRandomize();
echo $o->DoRnd();
PS
To much more secure random sequense, you can use
Private Declare Function CryptGenRandom Lib "advapi32.dll" _
(ByVal hProv As Long, ByVal dwLen As Long, ByVal pbBuffer As String) As Long
Her is a brief explanation how Rnd and Randomize works:
Rnd algorithm is well-known and published by MS at http://support.microsoft.com/kb/q231847/
Though MS claimed, that
>>Note that the above algorithm cannot be implemented in Visual Basic code in such a way that the random number sequence generated by the RND function can be reproduced.<<
in this article, here is VB implementation of this:
'=======bas module====
Private Const rnd_initial = 327680 '&H50000
Private Const two12 = &H1000& '2^12
Private Const two12minus1 = two12 - 1 '2^12-1
Private Const two24 = two12 * two12 '2^24
'MS values for a and c coeff and their lo/high words to avoid overflow error when rnd calculated
Private Const a = 1140671485, a0 = a Mod two12, a1 = a \ two12
Private Const c = 12820163, c0 = c Mod two12, c1 = c \ two12
Dim last_value As Double 'Unfortunately, VB doesn't allow init it here, like
'Dim last_value As Double = rnd_initial
Dim bRandomize As Boolean 'so we need this trick with boolean variable
Public Function My_Rnd(Optional ByVal number As Single = 1) As Single
If Not bRandomize And (last_value = 0) Then 'Init last_value with default &H50000
last_value = rnd_initial
bRandomize = True
End If
If number = 0 Then 'Rnd(0) simply return last Rnd
My_Rnd = last_value / two24
Exit Function
End If
If number < 0 Then 'TODO: Implement MS Xored algorithm
MsgBox "Not implemented yet"
End If
Dim s0 As Long, s1 As Long
s0 = last_value And two12minus1
s1 = last_value \ two12
last_value = (s0 * a0 + c0) + ((s0 * a1 + s1 * a0 + c1) And two12minus1) * two12
If last_value > two24 Then last_value = last_value - two24
My_Rnd = last_value / two24
End Function
'========Form code======
Private Sub Command1_Click()
For i = 1 To 100
a = My_Rnd
b = Rnd
Debug.Print a, b, IIf(a = b, "Same", "Not same")
Next i
End Sub
'=========================
So you can see that both code produce same sequence.
But MS add additional futures to its PRNG:
1. Call Rnd with negative number return some value, using MS crypto algorithm (not published). IMHO this is some simple Xored algorithm, I'll try to disassembly VBA6.dll and/or msvbvm and find this algorithm. In this case last_value doesn't change.
2. Randomize also use same (or near same) algorithm to set initial last_value for futher sequence.
So, if you need just normal distribution for some math investigations - use above code. If you try to use Rnd for some crypto algorithm - I suggest you choose another algorithm (BTW, Mersenne Twister also isn't the best (though better then VB Rnd), since it's well-known)