tandem rng tandem-hs GitHub

API

Use

import Data.Vector.Unboxed qualified as U
import Data.Word (Word32)
import System.Random.Tandem qualified as T

example :: (Double, Word32, T.Tandem)
example =
  let g0 = T.seed 42                       -- 128-bit seed, K = 32
      (x, g1) = T.nextDouble g0            -- uniform in [0, 1)
      (k, g2) = T.nextBelow32 10 g1        -- uniform in [0, 10), Lemire
      (zs, g3) = T.fillNormal 1000 g2      -- unboxed vector of standard normals
      worker = T.split 7 g3                -- by index, from the key alone
      (kids, g4) = T.fork 4 g3             -- from the current block, the parent moves on
   in (x + U.sum zs, k, g4)

Reference

random

Tandem is a RandomGen and a SplitGen of random 1.3, so random's adapters make it a StatefulGen:

import System.Random.Stateful

roll :: IO Word32
roll = do
  gen <- newIOGenM (T.seed 42)
  uniformRM (1, 6) gen

genWord8, genWord16, genWord32 and genWord64 draw their widths from the stream. genWord32R and genWord64R use Lemire's method with the width from the range, so genWord64R with a range up to 2^32 equals genWord32R. splitGen is fork 1.

Parallel use

Element i of a fill is draw i, so any decomposition reproduces a serial run. See Appendix B.