?
Solved

Random Number Generator for PHP and VB6 (PRNG)

Posted on 2006-10-26
4
Medium Priority
?
1,517 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
4 Comments
 
LVL 28

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 28

Accepted Solution

by:
Ark earned 2000 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 28

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 28

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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses

777 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