~/bend-docscommunity

spec/math/random/pcg.bend source

spec/math/random/pcg.bend on the hub · documented module

import Baseimport ../../lib/common.bend as C# Executable specification of Go's PCG (math/rand/v2 pcg.go; O'Neill, "PCG:# A Family of Simple Fast Space-Efficient Statistically Good Algorithms for# Random Number Generation", 2014, with the DXSM output function of numpy# and Go) on natural numbers:##   lcg(mul, inc, s)       one step of the 128-bit state: s * mul + inc#                          mod 2^128#   dxsm(cm, hi, lo)       the output of the state hi * 2^64 + lo:#                          hi ^= hi >> 32; hi *= cm (dxsm1); then#                          hi ^= hi >> 48; hi *= lo | 1 (dxsm3), each#                          product mod 2^64## Go's constants are mul = 2549297995355413924 * 2^64 + 4865540595714422341,# inc = 6364136223846793005 * 2^64 + 1442695040888963407 and# cm = 0xda942042e4dd58b5 (src/math/random/pcg.bend holds them as 64-bit# words); the functions take them as parameters, so no closed 64-bit# constant is ever expanded by the checker (spec/lib/common.bend).def b2n(b: Bool) -> Nat:  match b:    case True{}:      1n    case False{}:      0n# the exclusive or of the low w bits of a and bdef xor_bits(w: Nat, +a: Nat, +b: Nat) -> Nat:  match w:    case 0n:      0n    case 1n+k:      Nat.add(b2n(Bool.not(Nat.is_eq(C.bit(a), C.bit(b)))), Nat.double(xor_bits(k, C.half(a), C.half(b))))def lcg(+mul: Nat, +inc: Nat, +s: Nat) -> Nat:  C.low(128n, Nat.add(Nat.mul(s, mul), inc))def dxsm3(+h: Nat, +lo: Nat) -> Nat:  C.low(64n, Nat.mul(xor_bits(64n, h, C.high(48n, h)), Nat.add(Nat.double(C.half(lo)), 1n)))# the first half: hi ^= hi >> 32; hi *= cmdef dxsm1(+cm: Nat, +hi: Nat) -> Nat:  C.low(64n, Nat.mul(xor_bits(64n, hi, C.high(32n, hi)), cm))def dxsm(+cm: Nat, +hi: Nat, +lo: Nat) -> Nat:  dxsm3(dxsm1(cm, hi), lo)