Solved

Random Number Generator for PHP and VB6 (PRNG)

Posted on 2006-10-26
4
1,433 Views
Last Modified: 2008-09-12
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
 
0
Comment
Question by:deming
  • 4
4 Comments
 
LVL 27

Expert Comment

by:Ark
ID: 17823314
Hi
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)
0
 
LVL 27

Accepted Solution

by:
Ark earned 500 total points
ID: 17823901
Hi again!

Here is complete MS Randomize/Rnd implementation:

'=========bas module code=========
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)

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
Private Const two24minus1 = two24 - 1 '2^24-1
'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

Public Sub My_Randomize(Optional ByVal init_val As Variant)
    Dim dblInit As Double
    If IsMissing(init_val) Then init_val = Timer
    dblInit = CDbl(init_val)
    Call DoRandom("Randomize", 0, 0, dblInit)
End Sub

Public Function My_Rnd(Optional ByVal number As Single = 1) As Single
   Dim res As Long
   Call DoRandom("Rnd", res, number, 0)
   My_Rnd = res / two24
End Function

Private Sub DoRandom(ByVal Action As String, ByRef Result As Long, _
                     ByVal m As Single, ByVal n As Double)
   Static bInit As Boolean
   Static last_value As Long
   Dim l As Long, s0 As Long, s1 As Long
   
   If Not bInit Then
      last_value = rnd_initial
      bInit = True
   End If
   Select Case Action
      Case "Rnd"
           If m <> 0 Then
              If m < 0 Then
                CopyMemory s0, m, 3
                CopyMemory s1, ByVal VarPtr(m) + 3, 1
                last_value = s0 + s1 And two24minus1
              End If
              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
           End If
           Result = last_value
      Case "Randomize"
           CopyMemory l, ByVal VarPtr(n) + 4, 4
           last_value = ((l And 65535) Xor (l \ 65536)) * 256 Or _
                        (last_value And 255) And two24minus1
      Case Else
   End Select
End Sub

'==========Form code========
Private Sub Command1_Click()
   Dim a, b
   a = Timer
   Randomize a
   My_Randomize a
   For i = 1 To 100
      a = My_Rnd
      b = Rnd
      Debug.Print a, b, IIf(a = b, "Same", "Not same")
   Next i
End Sub

Private Sub Command2_Click()
   My_Rnd (-67)
   My_Randomize (67)
   a = My_Rnd()

   Rnd (-67)
   Randomize (67)
   b = Rnd()
   
   If a <> b Then
      Debug.Print "ERROR: Sequence is not the same :("
   Else
      Debug.Print "Bingo! The are the same! :)"
   End If
End Sub
0
 
LVL 27

Expert Comment

by:Ark
ID: 17824080
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} :)))))
0
 
LVL 27

Expert Comment

by:Ark
ID: 17824857
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
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now