by Aaron Ballman

A great feature of REALbasic 2006r1 was the introduction of a many new integer data types. You can now use signed and unsigned integers of varying degrees of precision. This opens up a new realm of algorithms that can be implemented easily in REALbasic.

One such class of algorithms are random number generators. Typically, these involve a lot of math (obviously), and the math relies on a lot of integer functionality. For instance, it assumes that overflow behaves a certain way, that math on unsigned integers behaves a certain way, etc. Since REALbasic has introduced all of these new data types, I wanted to chance to test them out. So I decided to implement the Mersenne twister pseudo-random number generation algorithm.

If you're interested in learning more about what the Mersenne twister algorithm is, I suggest checking out the Wiki for the algorithm. It has a good run-down of the concept, with links to even more in-depth information.

However, you're probably interested in the REALbasic implementation itself. The bulk of the algorithm exists in two functions -- the initialization and the 32-bit number generator.

Sub InitByArray(ParamArray init_key as UInt32)
  dim i, j, k as Integer

  dim key_length as Integer = UBound( init_key ) + 1

  init_genrand( 19650218 )

  i = 1
  j = 0
  if N > key_length then k = N else k = key_length

  while k > 0
    mt( i ) = Bitwise.BitXor( mt( i ), (Bitwise.BitXor( mt( i - 1 ), Bitwise.ShiftRight( mt( i - 1 ), 30 ) ) * 1664525) ) + init_key( j ) + j

    ' Again, I don't think this is needed for RB
    'mt( i ) = Bitwise.BitAnd( mt( i ), &hffffffff )

    i = i + 1
    j = j + 1

    if i >= N then
      mt( 0 ) = mt( N - 1)
      i = 1
    end if

    if j >= key_length then j = 0

    k = k - 1
  wend

  for k = N - 1 downto 0
    mt( i ) = Bitwise.BitXor( mt( i ), (Bitwise.BitXor( mt( i - 1 ), Bitwise.ShiftRight( mt( i - 1 ), 30 ) ) * 1566083941) ) - i

    ' Again, I don't think this is needed for RB
    'mt( i ) = Bitwise.BitAnd( mt( i ), &hffffffff )

    i = i + 1

    if i >= N then
      mt( 0 ) = mt( N - 1 )
      i = 1
    end if
  next k

  mt( 0 ) = &h80000000 // MSB is 1; assuring non-zero initial array
End Sub

Function RandInt32() As UInt32
  // generates a random number on [0,0xffffffff]-interval

  Dim y as UInt32
  static mag01( 2 ) as UInt32 = Array( UInt32( &h0 ), UInt32( MATRIX_A ) )

  if mti >= N then
    dim kk as Integer

    // If init_genrand hasn't been called yet
    if mti = N + 1 then init_genrand( 5489 )  // Use the default seed

    for kk = 0 to N - M - 1
      y = Bitwise.BitOr( Bitwise.BitAnd( mt( kk ), UPPER_MASK ), Bitwise.BitAnd( mt( kk + 1 ), LOWER_MASK ) )
      mt( kk ) = Bitwise.BitXor( Bitwise.BitXor( mt( kk + M ), Bitwise.ShiftRight( y, 1 ) ), mag01( Bitwise.BitAnd( y, &h1 ) ) )
    next kk

    for kk = kk to N - 1 - 1
      y = Bitwise.BitOr( Bitwise.BitAnd( mt( kk ), UPPER_MASK ), Bitwise.BitAnd( mt( kk + 1 ), LOWER_MASK ) )
      mt( kk ) = Bitwise.BitXor( Bitwise.BitXor( mt( kk + (M - N) ), Bitwise.ShiftRight( y, 1 ) ), mag01( Bitwise.BitAnd( y, &h1 ) ) )
    next kk

    y = Bitwise.BitOr( Bitwise.BitAnd( mt( N - 1 ), UPPER_MASK ), Bitwise.BitAnd( mt( 0 ), LOWER_MASK ) )
    mt( N - 1 ) = Bitwise.BitXOr( Bitwise.BitXor( mt( M - 1 ), Bitwise.ShiftRight( y, 1 ) ), mag01( Bitwise.BitAnd( y, &h1 ) ) )

    mti = 0
  end if

  y = mt( mti )
  mti = mti + 1

  // Tempering
  y = Bitwise.BitXor( y, Bitwise.ShiftRight( y, 11 ) )
  y = Bitwise.BitXor( y, Bitwise.BitAnd( Bitwise.ShiftLeft( y, 7 ), &h9d2c5680 ) )
  y = Bitwise.BitXor( y, Bitwise.BitAnd( Bitwise.ShiftLeft( y, 15 ), &hefc60000 ) )
  y = Bitwise.BitXor( y, Bitwise.ShiftRight( y, 18 ) )

  return y
End Function

Most of the other methods rely on these two to generate the random numbers. I won't (couldn't) go into the math behind the algorithm. I trust in the fact that this is a fairly standard algorithm implemented in many other languages for various uses. I ported my code directly from C code found here. If you spot any bugs in my code, or have any questions, please contact me at aaron@aaronballman.com