MRG32k3a Combined recursive generator (pseudo-code)

   /* Constants */
   /* First generator */
   a1 = [0, 1403580, -810728]
   m1 = 2**32 - 209
   /* Second Generator */
   a2 = [527612, 0, -1370589]
   m2 = 2**32 - 22853
    
   d = m1 + 1
   
   class MRG32k3a
       x1 = [0, 0, 0]  /* list of three last values of gen #1 */
       x2 = [0, 0, 0]  /* list of three last values of gen #2 */
       
       method seed(u64 seed_state)
           assert seed_state in range >0 and < d 
           x1 = [seed_state, 0, 0]
           x2 = [seed_state, 0, 0]
       end method
           
       method next_int()
           x1i = (a1[0]*x1[0] + a1[1]*x1[1] + a1[2]*x1[2]) mod m1
           x2i = (a2[0]*x2[0] + a2[1]*x2[1] + a2[2]*x2[2]) mod m2
           x1 = [x1i, x1[0], x1[1]]    /* Keep last three */
           x2 = [x2i, x2[0], x2[1]]    /* Keep last three */
           z = (x1i - x2i) % m1
           answer = (z + 1)
           
           return answer
       end method
       
       method next_float():
           return float next_int() / d
       end method
       
   end class


MRG32k3a Use:
   random_gen = instance MRG32k3a
   random_gen.seed(1234567)
   print(random_gen.next_int())   /* 1459213977 */
   print(random_gen.next_int())   /* 2827710106 */
   print(random_gen.next_int())   /* 4245671317 */
   print(random_gen.next_int())   /* 3877608661 */
   print(random_gen.next_int())   /* 2595287583 */
   
       

Task
 Generate a class/set of functions that generates pseudo-random
numbers as shown above.

 Show that the first five integers generated with the seed `1234567`
are as shown above

 Show that for an initial seed of '987654321' the counts of 100_000
repetitions of

   floor(random_gen.next_float() * 5)

Is as follows:

   0: 20002, 1: 20060, 2: 19948, 3: 20059, 4: 19931

 Show your output here, on this page.


import algorithm, math, sequtils, strutils, tables
 
const
  # First generator.
  a1 = [int64 0, 1403580, -810728]
  m1: int64 = 2^32 - 209
  # Second generator.
  a2 = [int64 527612, 0, -1370589]
  m2: int64 = 2^32 - 22853
 
  d = m1 + 1
 
type MRG32k3a = object
  x1: array[3, int64]   # List of three last values of gen #1.
  x2: array[3, int64]   # List of three last values of gen #2.
 
 
func seed(gen: var MRG32k3a; seedState: int64) =
  assert seedState in 1..<d
  gen.x1 = [seedState, 0, 0]
  gen.x2 = [seedState, 0, 0]
 
func nextInt(gen: var MRG32k3a): int64 =
  let x1i = floormod(a1[0] * gen.x1[0] + a1[1] * gen.x1[1] + a1[2] * gen.x1[2], m1)
  let x2i = floormod(a2[0] * gen.x2[0] + a2[1] * gen.x2[1] + a2[2] * gen.x2[2], m2)
  # In version 1.4, the following two lines doesn't work.
  # gen.x1 = [x1i, gen.x1[0], gen.x1[1]]    # Keep last three.
  # gen.x2 = [x2i, gen.x2[0], gen.x2[1]]    # Keep last three.
  gen.x1[2] = gen.x1[1]; gen.x1[1] = gen.x1[0]; gen.x1[0] = x1i
  gen.x2[2] = gen.x2[1]; gen.x2[1] = gen.x2[0]; gen.x2[0] = x2i
  result = floormod(x1i - x2i, m1) + 1
 
func nextFloat(gen: var MRG32k3a): float =
  gen.nextInt().float / d.float
 
when isMainModule:
  var gen: MRG32k3a
 
  gen.seed(1234567)
  for _ in 1..5:
    echo gen.nextInt()
 
  echo ""
  gen.seed(987654321)
  var counts: CountTable[int]
  for _ in 1..100_000:
    counts.inc int(gen.nextFloat() * 5)
  echo sorted(toSeq(counts.pairs)).mapIt($it[0] & ": " & $it[1]).join(", ")