Pseudo-random numbers/PCG32

From Rosetta Code
Revision as of 12:27, 28 February 2021 by Walterpachl (talk | contribs) (add REXX (for the "fun" of it)
Task
Pseudo-random numbers/PCG32
You are encouraged to solve this task according to the task description, using any language you may know.
Some definitions to help in the explanation
Floor operation
https://en.wikipedia.org/wiki/Floor_and_ceiling_functions
Greatest integer less than or equal to a real number.
Bitwise Logical shift operators (c-inspired)
https://en.wikipedia.org/wiki/Bitwise_operation#Bit_shifts
Binary bits of value shifted left or right, with zero bits shifted in where appropriate.
Examples are shown for 8 bit binary numbers; most significant bit to the left.
<< Logical shift left by given number of bits.
E.g Binary 00110101 << 2 == Binary 11010100
>> Logical shift right by given number of bits.
E.g Binary 00110101 >> 2 == Binary 00001101
^ Bitwise exclusive-or operator
https://en.wikipedia.org/wiki/Exclusive_or
Bitwise comparison for if bits differ
E.g Binary 00110101 ^ Binary 00110011 == Binary 00000110
| Bitwise or operator
https://en.wikipedia.org/wiki/Bitwise_operation#OR
Bitwise comparison gives 1 if any of corresponding bits are 1
E.g Binary 00110101 | Binary 00110011 == Binary 00110111


PCG32 Generator (pseudo-code)

PCG32 has two unsigned 64-bit integers of internal state:

  1. state: All 2**64 values may be attained.
  2. sequence: Determines which of 2**63 sequences that state iterates through. (Once set together with state at time of seeding will stay constant for this generators lifetime).

Values of sequence allow 2**63 different sequences of random numbers from the same state.

The algorithm is given 2 U64 inputs called seed_state, and seed_sequence. The algorithm proceeds in accordance with the following pseudocode:-

const N<-U64 6364136223846793005
const inc<-U64 (seed_sequence << 1) | 1
state<-U64 ((inc+seed_state)*N+inc
do forever
  xs<-U32 (((state>>18)^state)>>27)
  rot<-INT (state>>59)
  OUTPUT U32 (xs>>rot)|(xs<<((-rot)&31))
  state<-state*N+inc
end do

Note that this an anamorphism – dual to catamorphism, and encoded in some languages as a general higher-order `unfold` function, dual to `fold` or `reduce`.

Task
  • Generate a class/set of functions that generates pseudo-random

numbers using the above.

  • Show that the first five integers generated with the seed 42, 54

are: 2707161783 2068313097 3122475824 2211639955 3215226955


  • Show that for an initial seed of 987654321, 1 the counts of 100_000 repetitions of
   floor(random_gen.next_float() * 5)
Is as follows:
   0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005
  • Show your output here, on this page.


11l

Translation of: Python

<lang 11l>T PCG32

  UInt64 state, inc
  F next_int()
     V old = .state
     .state = (old * 6364136223846793005) + .inc
     V shifted = UInt32(((old >> 18) (+) old) >> 27)
     V rot = UInt32(old >> 59)
     R (shifted >> rot) [|] (shifted << (((-)rot + 1) [&] 31))
  F seed(UInt64 seed_state, seed_sequence)
     .state = 0
     .inc = (seed_sequence << 1) [|] 1
     .next_int()
     .state += seed_state
     .next_int()
  F next_float()
     R Float(.next_int()) / (UInt64(1) << 32)

V random_gen = PCG32() random_gen.seed(42, 54) L 5

  print(random_gen.next_int())

random_gen.seed(987654321, 1) V hist = Dict(0.<5, i -> (i, 0)) L 100'000

  hist[Int(random_gen.next_float() * 5)]++

print(hist)</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955
[0 = 20049, 1 = 20022, 2 = 20115, 3 = 19809, 4 = 20005]

Ada

Ada solution using a package to encapsulate the PCG32 algorithm. <lang Ada>with Interfaces; use Interfaces;

package random_pcg32 is

  function Next_Int return Unsigned_32;
  function Next_Float return Long_Float;
  procedure Seed (seed_state : Unsigned_64; seed_sequence : Unsigned_64);

end random_pcg32; </lang>

<lang Ada>package body random_pcg32 is

  State : Unsigned_64 := 0;
  inc   : Unsigned_64 := 0;
  ----------------
  -- Next_State --
  ----------------
  procedure Next_State is
     N : constant Unsigned_64 := 6_364_136_223_846_793_005;
  begin
     State := State * N + inc;
  end Next_State;
  --------------
  -- Next_Int --
  --------------
  function Next_Int return Unsigned_32 is
     old     : Unsigned_64          := State;
     shifted : Unsigned_32;
     Rot     : Unsigned_64;
     answer  : Unsigned_32;
     Mask32  : constant Unsigned_64 := Unsigned_64 (Unsigned_32'Last);
  begin
     shifted := Unsigned_32((((old / 2**18) xor old) / 2**27) and Mask32);
     Rot     := old / 2**59;
     answer  :=
       Shift_Right (shifted, Integer (Rot)) or
       Shift_Left (shifted, Integer ((not Rot + 1) and 31));
     Next_State;
     return answer;
  end Next_Int;
  ----------------
  -- Next_Float --
  ----------------
  function Next_Float return Long_Float is
  begin
     return Long_Float (Next_Int) / (2.0**32);
  end Next_Float;
  ----------
  -- Seed --
  ----------
  procedure Seed (seed_state : Unsigned_64; seed_sequence : Unsigned_64) is
  begin
     State := 0;
     inc   := (2 * seed_sequence) or 1;
     Next_State;
     State := State + seed_state;
     Next_State;
  end Seed;

end random_pcg32; </lang>

<lang Ada>with Ada.Text_Io; use ADa.Text_io; with Interfaces; use Interfaces; with random_pcg32; use random_pcg32;

procedure Main_P is

  counts : array (0..4) of Natural := (Others => 0);
  J : Natural;

begin

  seed(42, 54);
  for I in 1..5 loop
     Put_Line(Unsigned_32'Image(Next_Int));
  end loop;
  New_Line;
  
  seed(987654321, 1);
  for I in 1..100_000 loop
     J := Natural(Long_Float'Floor(Next_Float * 5.0));
     Counts(J) := Counts(J) + 1;
  end loop;
  
  for I in Counts'Range loop
     Put_Line(I'Image & " :" & Counts(I)'Image);
  end loop;
  

end Main_P; </lang>

Output:
 2707161783
 2068313097
 3122475824
 2211639955
 3215226955

 0 : 20049
 1 : 20022
 2 : 20115
 3 : 19809
 4 : 20005

ALGOL 68

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32

<lang algol68>BEGIN # generate some pseudo random numbers using PCG32 #

   # note that although LONG INT is 64 bits in Algol 68G, LONG BITS is longer than 64 bits #
   LONG BITS state     :=     LONG 16r853c49e6748fea9b;
   LONG INT  inc       := ABS LONG 16rda3e39cb94b95bdb;
   LONG BITS mask 64    =     LONG 16rffffffffffffffff;
   LONG BITS mask 32    =     LONG 16rffffffff;
   LONG BITS mask 31    =     LONG 16r7fffffff;
   LONG INT  one shl 32 = ABS ( LONG 16r1 SHL 32 );
   # XOR and assign convenience operator #
   PRIO XORAB = 1;
   OP   XORAB = ( REF LONG BITS x, LONG BITS v )REF LONG BITS: x := ( x XOR v ) AND mask 64;
   # initialises the state to the specified seed #
   PROC seed = ( LONG INT seed state, seed sequence )VOID:
        BEGIN
           state := 16r0;
           inc   := ABS ( ( ( BIN seed sequence SHL 1 ) OR 16r1 ) AND mask 64 );
           next int;
           state := SHORTEN ( BIN ( ABS state + seed state ) AND mask 64 );
           next int
        END # seed # ;
   # gets the next pseudo random integer #
   PROC next int = LONG INT:
        BEGIN
           LONG BITS old     = state;
           LONG INT const    = LONG 6364136223846793005;
           state            := SHORTEN ( mask 64 AND BIN ( ( ABS old * LENG const ) + inc ) );
           LONG BITS x      := old;
           x XORAB ( old SHR 18 );
           BITS  xor shifted = SHORTEN ( mask 32 AND ( x SHR 27 ) );
           INT   rot         = SHORTEN ABS ( mask 32 AND ( old SHR 59 ) );
           INT   rot 2       = IF rot = 0 THEN 0 ELSE 32 - rot FI;
           BITS  xor shr    := SHORTEN ( mask 32 AND LENG ( xor shifted SHR rot ) );
           BITS  xor shl    := xor shifted;
           TO rot 2 DO
               xor shl      := SHORTEN ( ( mask 31 AND LENG xor shl ) SHL 1 )
           OD;
           ABS ( LENG xor shr OR LENG xor shl )
        END # next int # ;
   # gets the next pseudo random real #
   PROC next float = LONG REAL: next int / one shl 32;
   BEGIN # task test cases #
       seed( 42, 54 );
       print( ( whole( next int, 0 ), newline ) ); # 2707161783 #
       print( ( whole( next int, 0 ), newline ) ); # 2068313097 #
       print( ( whole( next int, 0 ), newline ) ); # 3122475824 #
       print( ( whole( next int, 0 ), newline ) ); # 2211639955 #
       print( ( whole( next int, 0 ), newline ) ); # 3215226955 #
       # count the number of occurances of 0..4 in a sequence of pseudo random reals scaled to be in [0..5) #
       seed( 987654321, 1 );
       [ 0 : 4 ]INT counts; FOR i FROM LWB counts TO UPB counts DO counts[ i ] := 0 OD;
       TO 100 000 DO counts[ SHORTEN ENTIER ( next float * 5 ) ] +:= 1 OD;
       FOR i FROM LWB counts TO UPB counts DO
           print( ( whole( i, -2 ), ": ", whole( counts[ i ], -6 ) ) )
       OD;
       print( ( newline ) )
   END

END</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955
 0:  20049 1:  20022 2:  20115 3:  19809 4:  20005

C

Translation of: Go

<lang c>#include <math.h>

  1. include <stdint.h>
  2. include <stdio.h>

const uint64_t N = 6364136223846793005;

static uint64_t state = 0x853c49e6748fea9b; static uint64_t inc = 0xda3e39cb94b95bdb;

uint32_t pcg32_int() {

   uint64_t old = state;
   state = old * N + inc;
   uint32_t shifted = (uint32_t)(((old >> 18) ^ old) >> 27);
   uint32_t rot = old >> 59;
   return (shifted >> rot) | (shifted << ((~rot + 1) & 31));

}

double pcg32_float() {

   return ((double)pcg32_int()) / (1LL << 32);

}

void pcg32_seed(uint64_t seed_state, uint64_t seed_sequence) {

   state = 0;
   inc = (seed_sequence << 1) | 1;
   pcg32_int();
   state = state + seed_state;
   pcg32_int();

}

int main() {

   int counts[5] = { 0, 0, 0, 0, 0 };
   int i;
   pcg32_seed(42, 54);
   printf("%u\n", pcg32_int());
   printf("%u\n", pcg32_int());
   printf("%u\n", pcg32_int());
   printf("%u\n", pcg32_int());
   printf("%u\n", pcg32_int());
   printf("\n");
   pcg32_seed(987654321, 1);
   for (i = 0; i < 100000; i++) {
       int j = (int)floor(pcg32_float() * 5.0);
       counts[j]++;
   }
   printf("The counts for 100,000 repetitions are:\n");
   for (i = 0; i < 5; i++) {
       printf("  %d : %d\n", i, counts[i]);
   }
   return 0;

}</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005

C++

Translation of: C

<lang cpp>#include <array>

  1. include <iostream>

class PCG32 { private:

   const uint64_t N = 6364136223846793005;
   uint64_t state = 0x853c49e6748fea9b;
   uint64_t inc = 0xda3e39cb94b95bdb;

public:

   uint32_t nextInt() {
       uint64_t old = state;
       state = old * N + inc;
       uint32_t shifted = (uint32_t)(((old >> 18) ^ old) >> 27);
       uint32_t rot = old >> 59;
       return (shifted >> rot) | (shifted << ((~rot + 1) & 31));
   }
   double nextFloat() {
       return ((double)nextInt()) / (1LL << 32);
   }
   void seed(uint64_t seed_state, uint64_t seed_sequence) {
       state = 0;
       inc = (seed_sequence << 1) | 1;
       nextInt();
       state = state + seed_state;
       nextInt();
   }

};

int main() {

   auto r = new PCG32();
   r->seed(42, 54);
   std::cout << r->nextInt() << '\n';
   std::cout << r->nextInt() << '\n';
   std::cout << r->nextInt() << '\n';
   std::cout << r->nextInt() << '\n';
   std::cout << r->nextInt() << '\n';
   std::cout << '\n';
   std::array<int, 5> counts{ 0, 0, 0, 0, 0 };
   r->seed(987654321, 1);
   for (size_t i = 0; i < 100000; i++) {
       int j = (int)floor(r->nextFloat() * 5.0);
       counts[j]++;
   }
   std::cout << "The counts for 100,000 repetitions are:\n";
   for (size_t i = 0; i < counts.size(); i++) {
       std::cout << "  " << i << " : " << counts[i] << '\n';
   }
   return 0;

}</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005

D

Translation of: C++

<lang d>import std.math; import std.stdio;

struct PCG32 { private:

   immutable ulong N = 6364136223846793005;
   ulong state = 0x853c49e6748fea9b;
   ulong inc = 0xda3e39cb94b95bdb;

public:

   void seed(ulong seed_state, ulong seed_sequence) {
       state = 0;
       inc = (seed_sequence << 1) | 1;
       nextInt();
       state = state + seed_state;
       nextInt();
   }
   uint nextInt() {
       ulong old = state;
       state = old * N + inc;
       uint shifted = cast(uint)(((old >> 18) ^ old) >> 27);
       uint rot = old >> 59;
       return (shifted >> rot) | (shifted << ((~rot + 1) & 31));
   }
   double nextFloat() {
       return (cast(double) nextInt()) / (1L << 32);
   }

}

void main() {

   auto r = PCG32();
   r.seed(42, 54);
   writeln(r.nextInt());
   writeln(r.nextInt());
   writeln(r.nextInt());
   writeln(r.nextInt());
   writeln(r.nextInt());
   writeln;
   auto counts = [0, 0, 0, 0, 0];
   r.seed(987654321, 1);
   foreach (_; 0..100_000) {
       int j = cast(int)floor(r.nextFloat() * 5.0);
       counts[j]++;
   }
   writeln("The counts for 100,000 repetitions are:");
   foreach (i,v; counts) {
       writeln("  ", i, " : ", v);
   }

}</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005

Delphi

Velthuis.BigIntegers[1] by Rudy Velthuis.

Translation of: Python

<lang Delphi> program PCG32_test;

{$APPTYPE CONSOLE} uses

 System.SysUtils,
 Velthuis.BigIntegers,
 System.Generics.Collections;

type

 TPCG32 = class
 public
   FState: BigInteger;
   FInc: BigInteger;
   mask64: BigInteger;
   mask32: BigInteger;
   k: BigInteger;
   constructor Create(seedState, seedSequence: BigInteger); overload;
   constructor Create(); overload;
   destructor Destroy; override;
   procedure Seed(seed_state, seed_sequence: BigInteger);
   function NextInt(): BigInteger;
   function NextIntRange(size: Integer): TArray<BigInteger>;
   function NextFloat(): Extended;
 end;

{ TPCG32 }

constructor TPCG32.Create(seedState, seedSequence: BigInteger); begin

 Create();
 Seed(seedState, seedSequence);

end;

constructor TPCG32.Create; begin

 k := '6364136223846793005';
 mask64 := (BigInteger(1) shl 64) - 1;
 mask32 := (BigInteger(1) shl 32) - 1;
 FState := 0;
 FInc := 0;

end;

destructor TPCG32.Destroy; begin

 inherited;

end;

function TPCG32.NextFloat: Extended; begin

 Result := (NextInt.AsExtended / (BigInteger(1) shl 32).AsExtended);

end;

function TPCG32.NextInt(): BigInteger; var

 old, xorshifted, rot, answer: BigInteger;

begin

 old := FState;
 FState := ((old * k) + FInc) and mask64;
 xorshifted := (((old shr 18) xor old) shr 27) and mask32;
 rot := (old shr 59) and mask32;
 answer := (xorshifted shr rot.AsInteger) or (xorshifted shl ((-rot) and
   BigInteger(31)).AsInteger);
 Result := answer and mask32;

end;

function TPCG32.NextIntRange(size: Integer): TArray<BigInteger>; var

 i: Integer;

begin

 SetLength(Result, size);
 if size = 0 then
   exit;
 for i := 0 to size - 1 do
   Result[i] := NextInt;

end;

procedure TPCG32.Seed(seed_state, seed_sequence: BigInteger); begin

 FState := 0;
 FInc := ((seed_sequence shl 1) or 1) and mask64;
 nextint();
 Fstate := (Fstate + seed_state);
 nextint();

end;

var

 PCG32: TPCG32;
 i, key: Integer;
 count: TDictionary<Integer, Integer>;

begin

 PCG32 := TPCG32.Create(42, 54);
 for i := 0 to 4 do
   Writeln(PCG32.NextInt().ToString);
 PCG32.seed(987654321, 1);
 count := TDictionary<Integer, Integer>.Create();
 for i := 1 to 100000 do
 begin
   key := Trunc(PCG32.NextFloat * 5);
   if count.ContainsKey(key) then
     count[key] := count[key] + 1
   else
     count.Add(key, 1);
 end;
 Writeln(#10'The counts for 100,000 repetitions are:');
 for key in count.Keys do
   Writeln(key, ' : ', count[key]);
 count.free;
 PCG32.free;
 Readln;

end. </lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
3 : 19809
0 : 20049
4 : 20005
2 : 20115
1 : 20022

F#

The Functions

<lang fsharp> // PCG32. Nigel Galloway: August 13th., 2020 let N=6364136223846793005UL let seed n g=let g=g<<<1|||1UL in (g,(g+n)*N+g) let pcg32=Seq.unfold(fun(n,g)->let rot,xs=uint32(g>>>59),uint32(((g>>>18)^^^g)>>>27) in Some(uint32((xs>>>(int rot))|||(xs<<<(-(int rot)&&&31))),(n,g*N+n))) let pcgFloat n=pcg32 n|>Seq.map(fun n-> (float n)/4294967296.0) </lang>

The Tasks

<lang fsharp> pcg32(seed 42UL 54UL)|>Seq.take 5|>Seq.iter(printfn "%d") </lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

<lang fsharp> pcgFloat(seed 987654321UL 1UL)|>Seq.take 100000|>Seq.countBy(fun n->int(n*5.0))|>Seq.iter(printf "%A");printfn "" </lang>

(2, 20115)(3, 19809)(0, 20049)(4, 20005)(1, 20022)

Factor

Translation of: Python
Works with: Factor version 0.99 2020-08-14

<lang factor>USING: accessors kernel locals math math.bitwise math.statistics prettyprint sequences ;

CONSTANT: const 6364136223846793005

TUPLE: pcg32 state inc ;

<pcg32> ( -- pcg32 )
   0x853c49e6748fea9b 0xda3e39cb94b95bdb pcg32 boa ;
next-int ( pcg -- n )
   pcg state>> :> old
   old const * pcg inc>> + 64 bits pcg state<<
   old -18 shift old bitxor -27 shift 32 bits :> shifted
   old -59 shift 32 bits :> r
   shifted r neg shift
   shifted r neg 31 bitand shift bitor 32 bits ;
next-float ( pcg -- x ) next-int 1 32 shift /f ;
seed ( pcg st seq -- )
   0x0 pcg state<<
   seq 0x1 shift 1 bitor 64 bits pcg inc<<
   pcg next-int drop
   pcg state>> st + pcg state<<
   pcg next-int drop ;

! Task <pcg32> 42 54 [ seed ] keepdd 5 [ dup next-int . ] times

987654321 1 [ seed ] keepdd 100,000 [ dup next-float 5 * >integer ] replicate nip histogram .</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955
H{ { 0 20049 } { 1 20022 } { 2 20115 } { 3 19809 } { 4 20005 } }

Go

Translation of: Python

<lang go>package main

import (

   "fmt"
   "math"

)

const CONST = 6364136223846793005

type Pcg32 struct{ state, inc uint64 }

func Pcg32New() *Pcg32 { return &Pcg32{0x853c49e6748fea9b, 0xda3e39cb94b95bdb} }

func (pcg *Pcg32) seed(seedState, seedSequence uint64) {

   pcg.state = 0
   pcg.inc = (seedSequence << 1) | 1
   pcg.nextInt()
   pcg.state = pcg.state + seedState
   pcg.nextInt()

}

func (pcg *Pcg32) nextInt() uint32 {

   old := pcg.state
   pcg.state = old*CONST + pcg.inc
   pcgshifted := uint32(((old >> 18) ^ old) >> 27)
   rot := uint32(old >> 59)
   return (pcgshifted >> rot) | (pcgshifted << ((-rot) & 31))

}

func (pcg *Pcg32) nextFloat() float64 {

   return float64(pcg.nextInt()) / (1 << 32)

}

func main() {

   randomGen := Pcg32New()
   randomGen.seed(42, 54)
   for i := 0; i < 5; i++ {
       fmt.Println(randomGen.nextInt())
   }
   var counts [5]int
   randomGen.seed(987654321, 1)
   for i := 0; i < 1e5; i++ {
       j := int(math.Floor(randomGen.nextFloat() * 5))
       counts[j]++
   }
   fmt.Println("\nThe counts for 100,000 repetitions are:")
   for i := 0; i < 5; i++ {
       fmt.Printf("  %d : %d\n", i, counts[i])
   }

}</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005

Java

Translation of: C++

<lang java>public class PCG32 {

   private static final long N = 6364136223846793005L;
   private long state = 0x853c49e6748fea9bL;
   private long inc = 0xda3e39cb94b95bdbL;
   public void seed(long seedState, long seedSequence) {
       state = 0;
       inc = (seedSequence << 1) | 1;
       nextInt();
       state = state + seedState;
       nextInt();
   }
   public int nextInt() {
       long old = state;
       state = old * N + inc;
       int shifted = (int) (((old >>> 18) ^ old) >>> 27);
       int rot = (int) (old >>> 59);
       return (shifted >>> rot) | (shifted << ((~rot + 1) & 31));
   }
   public double nextFloat() {
       var u = Integer.toUnsignedLong(nextInt());
       return (double) u / (1L << 32);
   }
   public static void main(String[] args) {
       var r = new PCG32();
       r.seed(42, 54);
       System.out.println(Integer.toUnsignedString(r.nextInt()));
       System.out.println(Integer.toUnsignedString(r.nextInt()));
       System.out.println(Integer.toUnsignedString(r.nextInt()));
       System.out.println(Integer.toUnsignedString(r.nextInt()));
       System.out.println(Integer.toUnsignedString(r.nextInt()));
       System.out.println();
       int[] counts = {0, 0, 0, 0, 0};
       r.seed(987654321, 1);
       for (int i = 0; i < 100_000; i++) {
           int j = (int) Math.floor(r.nextFloat() * 5.0);
           counts[j]++;
       }
       System.out.println("The counts for 100,000 repetitions are:");
       for (int i = 0; i < counts.length; i++) {
           System.out.printf("  %d : %d\n", i, counts[i]);
       }
   }

}</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005

Julia

Translation of: Python

<lang julia>const mask32, CONST = 0xffffffff, UInt(6364136223846793005)

mutable struct PCG32

   state::UInt64
   inc::UInt64
   PCG32(st=0x853c49e6748fea9b, i=0xda3e39cb94b95bdb) = new(st, i)

end

"""return random 32 bit unsigned int""" function next_int!(x::PCG32)

   old = x.state
   x.state = (old * CONST) + x.inc
   xorshifted = (((old >> 18) ⊻ old) >> 27) & mask32
   rot = (old >> 59) & mask32
   return ((xorshifted >> rot) | (xorshifted << ((-rot) & 31))) & mask32

end

"""return random float between 0 and 1""" next_float!(x::PCG32) = next_int!(x) / (1 << 32)

function seed!(x::PCG32, st, seq)

   x.state = 0x0
   x.inc = (UInt(seq) << 0x1) | 1
   next_int!(x)
   x.state = x.state + UInt(st)
   next_int!(x)

end

function testPCG32()

   random_gen = PCG32()
   seed!(random_gen, 42, 54)
   for _ in 1:5
       println(next_int!(random_gen))
   end
   seed!(random_gen, 987654321, 1)
   hist = fill(0, 5)
   for _ in 1:100_000
       hist[Int(floor(next_float!(random_gen) * 5)) + 1] += 1
   end
   println(hist)
   for n in 1:5
       print(n - 1, ": ", hist[n], "  ")
   end

end

testPCG32()

</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955
[20049, 20022, 20115, 19809, 20005]
0: 20049  1: 20022  2: 20115  3: 19809  4: 20005

Kotlin

Translation of: C++

Requires the experimental unsigned feature for integer types <lang scala>import kotlin.math.floor

class PCG32 {

   private var state = 0x853c49e6748fea9buL
   private var inc = 0xda3e39cb94b95bdbuL
   fun nextInt(): UInt {
       val old = state
       state = old * N + inc
       val shifted = old.shr(18).xor(old).shr(27).toUInt()
       val rot = old.shr(59)
       return (shifted shr rot.toInt()) or shifted.shl((rot.inv() + 1u).and(31u).toInt())
   }
   fun nextFloat(): Double {
       return nextInt().toDouble() / (1L shl 32)
   }
   fun seed(seedState: ULong, seedSequence: ULong) {
       state = 0u
       inc = (seedSequence shl 1).or(1uL)
       nextInt()
       state += seedState
       nextInt()
   }
   companion object {
       private const val N = 6364136223846793005uL
   }

}

fun main() {

   val r = PCG32()
   r.seed(42u, 54u)
   println(r.nextInt())
   println(r.nextInt())
   println(r.nextInt())
   println(r.nextInt())
   println(r.nextInt())
   println()
   val counts = Array(5) { 0 }
   r.seed(987654321u, 1u)
   for (i in 0 until 100000) {
       val j = floor(r.nextFloat() * 5.0).toInt()
       counts[j] += 1
   }
   println("The counts for 100,000 repetitions are:")
   for (iv in counts.withIndex()) {
       println("  %d : %d".format(iv.index, iv.value))
   }

}</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005

Perl

<lang perl>use strict; use warnings; use feature 'say'; use Math::AnyNum qw(:overload);

package PCG32 {

   use constant {
       mask32 => 2**32 - 1,
       mask64 => 2**64 - 1,
       const  => 6364136223846793005,
   };
   sub new {
       my ($class, %opt) = @_;
       my $seed = $opt{seed} // 1;
       my $incr = $opt{incr} // 2;
       $incr = $incr << 1 | 1 & mask64;
       my $state = (($incr + $seed) * const + $incr) & mask64;
       bless {incr => $incr, state => $state}, $class;
   }
   sub next_int {
       my ($self) = @_;
       my $state  = $self->{state};
       my $shift  = ($state >> 18 ^ $state) >> 27 & mask32;
       my $rotate = $state >> 59 & mask32;
       $self->{state} = ($state * const + $self->{incr}) & mask64;
       ($shift >> $rotate) | $shift << (32 - $rotate) & mask32;
   }
   sub next_float {
       my ($self) = @_;
       $self->next_int / 2**32;
   }

}

say "Seed: 42, Increment: 54, first 5 values:"; my $rng = PCG32->new(seed => 42, incr => 54); say $rng->next_int for 1 .. 5;

say "\nSeed: 987654321, Increment: 1, values histogram:"; my %h; $rng = PCG32->new(seed => 987654321, incr => 1); $h{int 5 * $rng->next_float}++ for 1 .. 100_000; say "$_ $h{$_}" for sort keys %h;</lang>

Output:
Seed: 42, Increment: 54, first 5 values:
2707161783
2068313097
3122475824
2211639955
3215226955

Seed: 987654321, Increment: 1, values histogram:
0 20049
1 20022
2 20115
3 19809
4 20005

Phix

Phix proudly does not support the kind of "maths" whereby 255 plus 1 is 0 (or 127+1 is -128).
You can however achieve that with and_bits() in most cases, albeit limited to at most 32 bits.
Phix atoms are limited to 53/64 bits of precision, however (given the above) this task would need 128 bits.
First, for comparison only, this is the usual recommended native approach for this genre of task (different output) <lang Phix>puts(1,"NB: These are not expected to match the task spec!\n") set_rand(42) for i=1 to 5 do

   printf(1,"%d\n",rand(-1))

end for set_rand(987654321) sequence s = repeat(0,5) for i=1 to 100000 do

   s[floor(rnd()*5)+1] += 1

end for ?s</lang>

Output:
NB: These are not expected to match the task spec!
13007222
848581373
2714853861
808614160
2634828316
{20080,19802,19910,20039,20169}

To meet the spec, similar to the Delphi and Wren entries, we resort to using mpfr/gmp, but it is a fair bit longer, and slower, than the above. <lang Phix>include mpfr.e mpz const = mpz_init("6364136223846793005"),

   state = mpz_init("0x853c49e6748fea9b"),
     inc = mpz_init("0xda3e39cb94b95bdb"),   /* Always odd */
     b64 = mpz_init("0x10000000000000000"),  -- (truncate to 64 bits)
     b32 = mpz_init("0x100000000"),          -- (truncate to 32 bits)
     old = mpz_init(),
   xorsh = mpz_init()
   

procedure seed(integer seed_state, seed_sequence)

   mpz_set_si(inc,seed_sequence*2+1)
   -- as per the talk page:
   -- state := remainder((inc+seed_state)*const+inc,b64)
   mpz_add_ui(state,inc,seed_state)
   mpz_mul(state,state,const)
   mpz_add(state,state,inc)
   mpz_fdiv_r(state, state, b64) -- state := remainder(state,b64) 

end procedure

function next_int()

   mpz_set(old,state)          -- old := state
   mpz_set(state,inc)          -- state := inc
   mpz_addmul(state,old,const) -- state += old*const
   mpz_fdiv_r(state, state, b64) -- state := remainder(state,b64) 
   mpz_tdiv_q_2exp(xorsh, old, 18) -- xorsh := trunc(old/2^18)
   mpz_xor(xorsh, xorsh, old)      -- xorsh := xor_bits(xorsh,old)
   mpz_tdiv_q_2exp(xorsh, xorsh, 27) -- xorsh := trunc(xorsh/2^17)
   mpz_fdiv_r(xorsh, xorsh, b32)     -- xorsh := remainder(xorsh,b32) 
   atom xorshifted = mpz_get_atom(xorsh)
   mpz_tdiv_q_2exp(old, old, 59)           -- old := trunc(old/2^59)
   integer rot = mpz_get_integer(old)
   atom answer = xor_bitsu((xorshifted >> rot),(xorshifted << 32-rot))
   return answer

end function

function next_float()

   return next_int() / (1 << 32)

end function

seed(42, 54) for i=1 to 5 do

   printf(1,"%d\n",next_int())

end for seed(987654321,1) sequence r = repeat(0,5) for i=1 to 100000 do

   r[floor(next_float()*5)+1] += 1

end for ?r</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955
{20049,20022,20115,19809,20005}

Python

Python: As class

<lang python>mask64 = (1 << 64) - 1 mask32 = (1 << 32) - 1 CONST = 6364136223846793005


class PCG32():

   def __init__(self, seed_state=None, seed_sequence=None):
       if all(type(x) == int for x in (seed_state, seed_sequence)):
           self.seed(seed_state, seed_sequence)
       else:
           self.state = self.inc = 0
   
   def seed(self, seed_state, seed_sequence):
       self.state = 0
       self.inc = ((seed_sequence << 1) | 1) & mask64
       self.next_int()
       self.state = (self.state + seed_state)
       self.next_int()
       
   def next_int(self):
       "return random 32 bit unsigned int"
       old = self.state
       self.state = ((old * CONST) + self.inc) & mask64
       xorshifted = (((old >> 18) ^ old) >> 27) & mask32
       rot = (old >> 59) & mask32
       answer = (xorshifted >> rot) | (xorshifted << ((-rot) & 31))
       answer = answer &mask32
       
       return answer
   
   def  next_float(self):
       "return random float between 0 and 1"
       return self.next_int() / (1 << 32)
   

if __name__ == '__main__':

   random_gen = PCG32()
   random_gen.seed(42, 54)
   for i in range(5):
       print(random_gen.next_int())
       
   random_gen.seed(987654321, 1)
   hist = {i:0 for i in range(5)}
   for i in range(100_000):
       hist[int(random_gen.next_float() *5)] += 1
   print(hist)</lang>
Output:
2707161783
2068313097
3122475824
2211639955
3215226955
{0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005}

Python: As generator

<lang python>def pcg32(seed_state=None, seed_sequence=None, as_int=True):

   def next_int():
       "return random 32 bit unsigned int"
       nonlocal state, inc
       state, xorshifted, rot = (((state * CONST) + inc) & mask64,
                                 (((state >> 18) ^ state) >> 27) & mask32,
                                 (state >> 59) & mask32)
       answer = (((xorshifted >> rot) | (xorshifted << ((-rot) & 31)))
                 & mask32)
       return answer
   # Seed
   state = inc = 0
   if all(type(x) == int for x in (seed_state, seed_sequence)):
       inc = ((seed_sequence << 1) | 1) & mask64
       next_int()
       state += seed_state
       next_int()
   while True:
       yield next_int() if as_int else next_int() / (1 << 32)


if __name__ == '__main__':

   from itertools import islice
   for i in islice(pcg32(42, 54), 5):
       print(i)
   hist = {i:0 for i in range(5)}
   for i in islice(pcg32(987654321, 1, as_int=False), 100_000):
       hist[int(i * 5)] += 1
   print(hist)</lang>
Output:
2707161783
2068313097
3122475824
2211639955
3215226955
{0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005}

Raku

Works with: Rakudo version 2020.07
Translation of: Python

Or... at least, it started out that way.

Raku does not have unsigned Integers at this time (Integers are arbitrary sized) so use explicit bit masks during bitwise operations.

<lang perl6>class PCG32 {

   has $!state;
   has $!incr;
   constant mask32 = 2³² - 1;
   constant mask64 = 2⁶⁴ - 1;
   constant const = 6364136223846793005;
   submethod BUILD (
       Int :$seed = 0x853c49e6748fea9b, # default seed
       Int :$incr = 0xda3e39cb94b95bdb  # default increment
     ) {
       $!incr  = $incr +< 1 +| 1 +& mask64;
       $!state = (($!incr + $seed) * const + $!incr) +& mask64;
   }
   method next-int {
       my $shift  = ($!state +> 18 +^ $!state) +> 27 +& mask32;
       my $rotate =  $!state +> 59 +& 31;
       $!state    = ($!state * const + $!incr) +& mask64;
       ($shift +> $rotate) +| ($shift +< (32 - $rotate) +& mask32)
   }
   method next-rat { self.next-int / 2³² }

}


  1. Test next-int with custom seed and increment

say 'Seed: 42, Increment: 54; first five Int values:'; my $rng = PCG32.new( :seed(42), :incr(54) ); .say for $rng.next-int xx 5;


  1. Test next-rat (since these are rational numbers by default)

say "\nSeed: 987654321, Increment: 1; first 1e5 Rat values histogram:"; $rng = PCG32.new( :seed(987654321), :incr(1) ); say ( ($rng.next-rat * 5).floor xx 100_000 ).Bag;


  1. Test next-int with default seed and increment

say "\nSeed: default, Increment: default; first five Int values:"; $rng = PCG32.new; .say for $rng.next-int xx 5;</lang>

Output:
Seed: 42, Increment: 54; first five Int values:
2707161783
2068313097
3122475824
2211639955
3215226955

Seed: 987654321, Increment: 1; first 1e5 Rat values histogram:
Bag(0(20049), 1(20022), 2(20115), 3(19809), 4(20005))

Seed: default, Increment: default; first five Int values:
465482994
3895364073
1746730475
3759121132
2984354868

REXX

Translation of: Java

It was a challenge to understand how some Java constructs work and to end up with the identical output. DON'T use Rexx, however, for this type of problem unless you take the time spent for some Java coffies! <lang rexx> Numeric Digits 40 Call time 'R' N = 6364136223846793005 state = x2d('853c49e6748fea9b',16) inc = x2d('da3e39cb94b95bdb',16) Call seed 42,54 Do zz=1 To 5

 res=nextint()
 Say int2str(res)
 End

Call seed 987654321,1 cnt.=0 Do i=1 To 100000

 z=nextfloat()
 cnt.z=cnt.z+1
 End

Say Say 'The counts for 100,000 repetitions are:' Do z=0 To 4

 Say format(z,2) ':' format(cnt.z,5)
 End

Say time('E') Exit

int2str: Procedure int=arg(1) intx=d2x(int,8) res=x2d(copies(0,8)intx,16) Return res

seed: Parse Arg seedState,seedSequence state=0 inc=dshift(seedSequence,-1) inc=x2d(or(d2x(inc,16),d2x(1,16)),16) z=nextint() state=javaadd(state,seedState) z=nextint() Return

nextInt: old = state oldxN = javamult(old,n) statex= javaadd(oldxN,inc) state=statex oldx=d2x(old,16) oldb=x2b(oldx) oldb18=copies(0,18)left(oldb,64-18) oldb18o=bxor(oldb18,oldb) rb=copies(0,27)left(oldb18o,64-27) rx=b2x(rb) shifted=x2d(substr(rx,9),8) oldx=d2x(old,16) oldb=x2b(oldx) oldb2=copies(0,59)left(oldb,length(oldb)-59) oldx2=b2x(oldb2) rotx=x2d(substr(oldx2,9),8) t1=dshift(shifted,rotx,'L') t2=x2d(xneg(d2x(rotx,8)),8) t3=t2+1 t4=x2d(xand(d2x(t3,8),d2x(31,8)),8) t5=dshift(shifted,-t4) t5x=d2x(t5,16) t5y=substr(t5x,9) t5z=x2d(t5y,16) t7=x2d(or(d2x(t1,16),d2x(t5z,16)),16) t8=long2int(t7) Return t8

nextfloat: ni=nextint() nix=d2x(ni,8) niz=copies(0,8)nix u=x2d(niz,16) uu=u/(2**32) z=uu*5%1 Return z

javaadd: Procedure /**********************************************************************

  • Add two long integers and ignore the possible overflow
                                                                                                                                            • /

Numeric Digits 40 Parse Arg a,b r=a+b rx=d2x(r,18) res=right(rx,16) return x2d(res,16)

javamult: Procedure /**********************************************************************

  • Multiply java style
                                                                                                                                            • /

Numeric Digits 40 Parse Arg a,b m=d2x(a*b,16) res=x2d(m,16) Return res

bxor: Procedure /**********************************************************************

  • Exclusive Or two bit strings
                                                                                                                                            • /

Parse arg a,b res= Do i=1 To length(a)

 res=res||(substr(a,i,1)<>substr(b,i,1))
 End

Return res

xxor: Procedure /**********************************************************************

  • Exclusive Or two hex strings
                                                                                                                                            • /

Parse Arg u,v ub=x2b(u) vb=x2b(v) res= Do i=1 To 64

 res=res||(substr(ub,i,1)<>substr(vb,i,1))
 End

res=b2x(res) Return res

xand: Procedure /**********************************************************************

  • And two hex strings
                                                                                                                                            • /

Parse Arg u,v ub=x2b(u) vb=x2b(v) res= Do i=1 To length(ub)

 res=res||(substr(ub,i,1)&substr(vb,i,1))
 End

res=b2x(res) Return res

or: Procedure /**********************************************************************

  • Or two hex strings
                                                                                                                                            • /

Parse Arg u,v ub=x2b(u) vb=x2b(v) res= Do i=1 To length(ub)

 res=res||(substr(ub,i,1)|substr(vb,i,1))
 End

res=b2x(res) Return res

long2int: Procedure /**********************************************************************

  • Cast long to int
                                                                                                                                            • /

Parse Arg long longx=d2x(long,16) int=x2d(substr(longx,9),8) Return int

xneg: Procedure /**********************************************************************

  • Negate a hex string
                                                                                                                                            • /

Parse Arg s sb=x2b(s) res= Do i=1 To length(sb)

 res=res||\substr(sb,i,1)
 End

res=b2x(res) Return res

dshift: Procedure /**********************************************************************

  • Implement the shift operations for a long variable
  • r = dshift(long,shift[,mode]) >> Mode='L' logical right shift
  • >>> Mode='A' arithmetic right shift
  • << xhift<0 left shift
                                                                                        • `*************************/

Parse Upper Arg n,s,o Numeric Digits 40 If o= Then o='L' nx=d2x(n,16) nb=x2b(nx) If s<0 Then Do

 s=abs(s)
 rb=substr(nb,s+1)||copies('0',s)
 rx=b2x(rb)
 r=x2d(rx,16)
 End

Else Do

 If o='L' Then Do
   If left(nb,1)=1 Then
     nb=copies(0,32)substr(nb,33)
   rb=left(copies('0',s)nb,length(nb))
   rx=b2x(rb)
   ry=left(rx,8)
   r=x2d(rx,16)
   End
 Else Do
   rb=left(copies(left(nb,1),s)nb,length(nb))
   rx=b2x(rb)
   r=x2d(rx,16)
   End
 End

Return r

b2x: Procedure Expose x. /**********************************************************************

  • Convert a Bit string to a Hex stríng
                                                                                                                                            • /

Parse Arg b z='0'; bits.z='0000'; y=bits.z; x.y=z z='1'; bits.z='0001'; y=bits.z; x.y=z z='2'; bits.z='0010'; y=bits.z; x.y=z z='3'; bits.z='0011'; y=bits.z; x.y=z z='4'; bits.z='0100'; y=bits.z; x.y=z z='5'; bits.z='0101'; y=bits.z; x.y=z z='6'; bits.z='0110'; y=bits.z; x.y=z z='7'; bits.z='0111'; y=bits.z; x.y=z z='8'; bits.z='1000'; y=bits.z; x.y=z z='9'; bits.z='1001'; y=bits.z; x.y=z z='A'; bits.z='1010'; y=bits.z; x.y=z z='B'; bits.z='1011'; y=bits.z; x.y=z z='C'; bits.z='1100'; y=bits.z; x.y=z z='D'; bits.z='1101'; y=bits.z; x.y=z z='E'; bits.z='1110'; y=bits.z; x.y=z z='F'; bits.z='1111'; y=bits.z; x.y=z x= Do While b<>

 Parse Var b b4 +4 b
 x=x||x.b4
 End

Return x

x2b: Procedure Expose bits. /***********************************************************************

  • Convert a Hex string to a Bit stríng
                                                                                                                                              • /

Parse Arg x z='0'; bits.z='0000'; y=bits.z; x.y=z z='1'; bits.z='0001'; y=bits.z; x.y=z z='2'; bits.z='0010'; y=bits.z; x.y=z z='3'; bits.z='0011'; y=bits.z; x.y=z z='4'; bits.z='0100'; y=bits.z; x.y=z z='5'; bits.z='0101'; y=bits.z; x.y=z z='6'; bits.z='0110'; y=bits.z; x.y=z z='7'; bits.z='0111'; y=bits.z; x.y=z z='8'; bits.z='1000'; y=bits.z; x.y=z z='9'; bits.z='1001'; y=bits.z; x.y=z z='A'; bits.z='1010'; y=bits.z; x.y=z z='B'; bits.z='1011'; y=bits.z; x.y=z z='C'; bits.z='1100'; y=bits.z; x.y=z z='D'; bits.z='1101'; y=bits.z; x.y=z z='E'; bits.z='1110'; y=bits.z; x.y=z z='F'; bits.z='1111'; y=bits.z; x.y=z b= Do While x<>

 Parse Var x c +1 x
 b=b||bits.c
 End

Return b </lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
 0 : 20049
 1 : 20022
 2 : 20115
 3 : 19809
 4 : 20005

Ruby

Translation of: Python

<lang Ruby>class PCG32

 MASK64 = (1 << 64) - 1
 MASK32 = (1 << 32) - 1
 CONST  = 6364136223846793005
 def seed(seed_state, seed_sequence)
   @state = 0
   @inc = ((seed_sequence << 1) | 1) & MASK64
   next_int
   @state = @state + seed_state
   next_int
 end
 
 def next_int
   old = @state
   @state = ((old * CONST) + @inc) & MASK64
   xorshifted = (((old >> 18) ^ old) >> 27) & MASK32
   rot = (old >> 59) & MASK32
   answer = (xorshifted >> rot) | (xorshifted << ((-rot) & 31))
   answer & MASK32
 end
 
 def next_float
   next_int.fdiv(1 << 32)
 end
 

end

random_gen = PCG32.new random_gen.seed(42, 54) 5.times{puts random_gen.next_int}

random_gen.seed(987654321, 1) p 100_000.times.each{(random_gen.next_float * 5).floor}.tally.sort.to_h </lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955
{0=>20049, 1=>20022, 2=>20115, 3=>19809, 4=>20005}

Sidef

Translation of: Perl

<lang ruby>class PCG32(seed, incr) {

   has state
   define (
       mask32 = (2**32 - 1),
       mask64 = (2**64 - 1),
       N      = 6364136223846793005,
   )
   method init {
       seed := 1
       incr := 2
       incr  = (((incr << 1) | 1) & mask64)
       state = (((incr + seed)*N + incr) & mask64)
   }
   method next_int {
       var shift  = ((((state >> 18) ^ state) >> 27) & mask32)
       var rotate = ((state >> 59) & mask32)
           state  = ((state*N + incr) & mask64)
       ((shift >> rotate) | (shift << (32-rotate))) & mask32
   }
   method next_float {
       self.next_int / (mask32+1)
   }

}

say "Seed: 42, Increment: 54, first 5 values:"; var rng = PCG32(seed: 42, incr: 54) say 5.of { rng.next_int }

say "\nSeed: 987654321, Increment: 1, values histogram:"; var rng = PCG32(seed: 987654321, incr: 1) var histogram = Bag(1e5.of { floor(5*rng.next_float) }...) histogram.pairs.sort.each { .join(": ").say }</lang>

Output:
Seed: 42, Increment: 54, first 5 values:
[2707161783, 2068313097, 3122475824, 2211639955, 3215226955]

Seed: 987654321, Increment: 1, values histogram:
0: 20049
1: 20022
2: 20115
3: 19809
4: 20005

Standard ML

<lang sml>type pcg32 = LargeWord.word * LargeWord.word

local

 infix 5 >>
 val op >> = LargeWord.>>
 and m = 0w6364136223846793005 : LargeWord.word
 and rotate32 = fn a as (x, n) =>
   Word32.orb (Word32.>> a, Word32.<< (x, Word.andb (~ n, 0w31)))

in

 fun pcg32Init (seed, seq) : pcg32 =
   let
     val inc = LargeWord.<< (LargeWord.fromInt seq, 0w1) + 0w1
   in
     ((LargeWord.fromInt seed + inc) * m + inc, inc)
   end
 fun pcg32Random ((state, inc) : pcg32) : Word32.word * pcg32 = (
   rotate32 (
     Word32.xorb (
       Word32.fromLarge (state >> 0w27),
       Word32.fromLarge (state >> 0w45)),
     Word.fromLarge (state >> 0w59)),
   (state * m + inc, inc))

end</lang>

Test code:

<lang sml>fun test1 (rand, state) =

 (print (Word32.fmt StringCvt.DEC rand ^ "\n"); state)

local

 val prependFormatted =
   fn (i, v, lst) => Int.toString i ^ ": " ^ Int.toString v :: lst
 and counts = IntArray.array (5, 0)

in

 fun test2 (rand, state) =
   let
     val i = LargeWord.toInt (LargeWord.>> (0w5 * Word32.toLarge rand, 0w32))
   in
     IntArray.update (counts, i, IntArray.sub (counts, i) + 1); state
   end
 fun test2res () =
   IntArray.foldri prependFormatted [] counts

end

fun doTimes (_, 0, state) = state

 | doTimes (f, n, state) = doTimes (f, n - 1, f state)

val _ = doTimes (test1 o pcg32Random, 5, pcg32Init (42, 54))

val _ = doTimes (test2 o pcg32Random, 100000, pcg32Init (987654321, 1)) val () = print ("\n" ^ ((String.concatWith ", " o test2res) ()) ^ "\n")</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005

Wren

Translation of: Python
Library: Wren-big

As Wren doesn't have a 64-bit integer type, we use BigInt instead. <lang ecmascript>import "/big" for BigInt

var Const = BigInt.new("6364136223846793005") var Mask64 = (BigInt.one << 64) - BigInt.one var Mask32 = (BigInt.one << 32) - BigInt.one

class Pcg32 {

   construct new() {
       _state  = BigInt.fromBaseString("853c49e6748fea9b", 16)
       _inc    = BigInt.fromBaseString("da3e39cb94b95bdb", 16)
   }
   seed(seedState, seedSequence) {
       _state = BigInt.zero
       _inc = ((seedSequence << BigInt.one) | BigInt.one) & Mask64
       nextInt
       _state = _state + seedState
       nextInt
   }
   nextInt {
       var old = _state
       _state = (old*Const + _inc) & Mask64
       var xorshifted = (((old >> 18) ^ old) >> 27) & Mask32
       var rot = (old >> 59) & Mask32
       return ((xorshifted >> rot) | (xorshifted << ((-rot) & 31))) & Mask32
   }
   nextFloat { nextInt.toNum / 2.pow(32) }

}

var randomGen = Pcg32.new() randomGen.seed(BigInt.new(42), BigInt.new(54)) for (i in 0..4) System.print(randomGen.nextInt)

var counts = List.filled(5, 0) randomGen.seed(BigInt.new(987654321), BigInt.one) for (i in 1..1e5) {

   var i = (randomGen.nextFloat * 5).floor
   counts[i] = counts[i] + 1

} System.print("\nThe counts for 100,000 repetitions are:") for (i in 0..4) System.print("  %(i) : %(counts[i])")</lang>

Output:
2707161783
2068313097
3122475824
2211639955
3215226955

The counts for 100,000 repetitions are:
  0 : 20049
  1 : 20022
  2 : 20115
  3 : 19809
  4 : 20005