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:

 state: All 2**64 values may be attained.
 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.


 
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.
 