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.
- https://en.wikipedia.org/wiki/Floor_and_ceiling_functions
- 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.
- https://en.wikipedia.org/wiki/Bitwise_operation#Bit_shifts
- << Logical shift left by given number of bits.
- E.g Binary 00110101 << 2 == Binary 11010100
- << Logical shift left by given number of bits.
- >> Logical shift right by given number of bits.
- E.g Binary 00110101 >> 2 == Binary 00001101
- >> Logical shift right by given number of bits.
- ^ 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 withstate
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
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)
- 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.
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;
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;
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;
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
ALGOL 68
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
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0: 20049 1: 20022 2: 20115 3: 19809 4: 20005
C
#include <math.h>
#include <stdint.h>
#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;
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
C#
using System;
class PCG32
{
private const ulong N = 6364136223846793005;
private ulong state = 0x853c49e6748fea9b;
private ulong inc = 0xda3e39cb94b95bdb;
public uint NextInt()
{
ulong old = state;
state = old * N + inc;
uint shifted = (uint)(((old >> 18) ^ old) >> 27);
uint rot = (uint)(old >> 59);
return (shifted >> (int)rot) | (shifted << (int)((~rot + 1) & 31));
}
public double NextFloat()
{
return ((double)NextInt()) / (1UL << 32);
}
public void Seed(ulong seedState, ulong seedSequence)
{
state = 0;
inc = (seedSequence << 1) | 1;
NextInt();
state += seedState;
NextInt();
}
}
class Program
{
static void Main(string[] args)
{
var r = new PCG32();
r.Seed(42, 54);
Console.WriteLine(r.NextInt());
Console.WriteLine(r.NextInt());
Console.WriteLine(r.NextInt());
Console.WriteLine(r.NextInt());
Console.WriteLine(r.NextInt());
Console.WriteLine();
int[] counts = new int[5];
r.Seed(987654321, 1);
for (int i = 0; i < 100000; i++)
{
int j = (int)Math.Floor(r.NextFloat() * 5.0);
counts[j]++;
}
Console.WriteLine("The counts for 100,000 repetitions are:");
for (int i = 0; i < counts.Length; i++)
{
Console.WriteLine($" {i} : {counts[i]}");
}
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
C++
#include <array>
#include <iostream>
#include <math.h>
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;
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
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);
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
Dart
import 'dart:math';
class PCG32 {
BigInt fState = BigInt.zero;
BigInt fInc = BigInt.zero;
final BigInt mask64 = (BigInt.one << 64) - BigInt.one;
final BigInt mask32 = (BigInt.one << 32) - BigInt.one;
final BigInt k = BigInt.parse('6364136223846793005');
PCG32(BigInt seedState, BigInt seedSequence) {
seed(seedState, seedSequence);
}
PCG32.noSeed() {
fState = BigInt.zero;
fInc = BigInt.zero;
}
void seed(BigInt seedState, BigInt seedSequence) {
fState = BigInt.zero;
fInc = ((seedSequence << 1) | BigInt.one) & mask64;
nextInt();
fState += seedState;
nextInt();
}
BigInt nextInt() {
BigInt old = fState;
fState = ((old * k) + fInc) & mask64;
BigInt xorshifted = ( ((old >> 18) ^ old) >> 27) & mask32;
BigInt rot = (old >> 59) & mask32;
BigInt shifted = (xorshifted >> rot.toInt()) | (xorshifted << ((-rot) & BigInt.from(31)).toInt());
return shifted & mask32;
}
double nextFloat() {
return nextInt().toDouble() / (BigInt.one << 32).toDouble();
}
List<BigInt> nextIntRange(int size) {
List<BigInt> result = [];
for (int i = 0; i < size; i++) {
result.add(nextInt());
}
return result;
}
}
void main() {
var pcg32 = PCG32(BigInt.from(42), BigInt.from(54));
for (int i = 0; i < 5; i++) {
print(pcg32.nextInt().toString());
}
pcg32.seed(BigInt.from(987654321), BigInt.one);
var count = <int, int>{};
for (int i = 0; i < 100000; i++) {
int key = (pcg32.nextFloat() * 5).truncate();
count[key] = (count[key] ?? 0) + 1;
}
print('\nThe counts for 100,000 repetitions are:');
count.forEach((key, value) {
print('$key : $value');
});
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 2 : 20115 3 : 19809 0 : 20049 4 : 20005 1 : 20022
Delphi
Velthuis.BigIntegers[1] by Rudy Velthuis.
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.
- 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
// 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)
The Tasks
pcg32(seed 42UL 54UL)|>Seq.take 5|>Seq.iter(printfn "%d")
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955
pcgFloat(seed 987654321UL 1UL)|>Seq.take 100000|>Seq.countBy(fun n->int(n*5.0))|>Seq.iter(printf "%A");printfn ""
(2, 20115)(3, 19809)(0, 20049)(4, 20005)(1, 20022)
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 .
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 H{ { 0 20049 } { 1 20022 } { 2 20115 } { 3 19809 } { 4 20005 } }
FreeBASIC
#define floor(x) ((x*2.0-0.5) Shr 1)
Const As Ulongint mask64 = &HFFFFFFFFFFFFFFFF
Const As Ulongint mask32 = &HFFFFFFFF
Const As Ulongint cte = 6364136223846793005
Dim Shared As Ulongint state, inc
Function next_int() As Ulongint
' return random 32 bit unsigned int
Dim As Ulongint old = state
state = ((old * cte) + inc) And mask64
Dim As Ulongint xorshifted = (((old Shr 18) Xor old) Shr 27) And mask32
Dim As Ulongint rot = (old Shr 59) And mask32
Dim As Ulongint answer = (xorshifted Shr rot) Or (xorshifted Shl ((-rot) And 31))
answer And= mask32
Return answer
End Function
Function next_float() As Double
' return random float between 0 and 1
Return next_int() / (2 ^ 32)
End Function
Sub seed(seed_state As Ulongint, seed_sequence As Ulongint)
state = 0
inc = ((seed_sequence Shl 1) Or 1) And mask64
next_int()
state = (state + seed_state) And mask64
next_int()
End Sub
Dim As Integer i, hist(4)
seed(42, 54)
For i = 1 To 5
Print next_int()
Next i
Print !"\nThe counts for 100,000 repetitions are:"
seed(987654321, 1)
For i = 1 To 100000
hist(floor(next_float() * 5)) += 1
Next i
For i = 0 To 4
Print Using "hist(#) = #####"; i; hist(i)
Next i
Sleep
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: hist(0) = 20049 hist(1) = 20022 hist(2) = 20115 hist(3) = 19809 hist(4) = 20005
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])
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
Haskell
Implement given algorithm as an instance of RandomGen
class.
import Data.Bits
import Data.Word
import System.Random
import Data.List
data PCGen = PCGen !Word64 !Word64
mkPCGen state sequence =
let
n = 6364136223846793005 :: Word64
inc = (sequence `shiftL` 1) .|. 1 :: Word64
in PCGen ((inc + state)*n + inc) inc
instance RandomGen PCGen where
next (PCGen state inc) =
let
n = 6364136223846793005 :: Word64
xs = fromIntegral $ ((state `shiftR` 18) `xor` state) `shiftR` 27 :: Word32
rot = fromIntegral $ state `shiftR` 59 :: Int
in (fromIntegral $ (xs `shiftR` rot) .|. (xs `shiftL` ((-rot) .&. 31))
, PCGen (state * n + inc) inc)
split _ = error "PCG32 is not splittable"
randoms' :: RandomGen g => g -> [Int]
randoms' g = unfoldr (pure . next) g
toFloat n = fromIntegral n / (2^32 - 1)
Direct usage of generator:
*Main> take 5 $ randoms' (mkPCGen 42 54) [2707161783,2068313097,3122475824,2211639955,3215226955] *Main> let hist = map length . group . sort *Main> hist . take 100000 $ (floor . (*5) . toFloat) <$> (randoms' (mkPCGen 987654321 1)) [20049,20022,20115,19809,20005]
Using Random
class gives different results due to internal shuffling:
*Main> take 5 $ randoms (mkPCGen 42 54) [2068313097,2211639955,3421331566,2167406445,4181216144] *Main>let hist = map length . group . sort *Main> hist . take 100000 $ (floor . (*5)) <$> (randoms (mkPCGen 987654321 1) :: [Float]) [20009,20065,20023,19876,20027]
J
Implementation:
PCG32GEN=: {{
g=. cocreate''
'state0__g seq__g'=. m
init__g=: {{
max=: 2^64x
u64=: &.((64#2x)&#:) NB. binary domain operation
U64=: max&| NB. integer domain result
U32=: (2^32)&(<.@|)
and=: *. u64
xor=: ~: u64
or=: +. u64
lsl=: max <.@| ] * 2x^[
N=: 6364136223846793005x
inc=: U64 1 2x p. seq
state=: U64 inc+N*inc+state0
}}
next__g=: g {{ m[y
xs=. U32 _27 lsl state xor _18 lsl state
rot=. -_59 lsl state
state=: U64 inc+N*state
U32 (rot lsl xs) or (31 and rot) lsl xs
}}
init__g''
(;'next_';(;g);'_')~
}}
next_float=: %&(2^32)
Task examples:
42 54 PCG32GEN ^:(1+i.5)''
2707161776 2068313120 3122475824 2211639955 3215226955
(~.,. #/.~) <.5*next_float 987654321 1 PCG32GEN^:(1+i.1e5) ''
2 20115
3 19809
0 20049
4 20005
1 20022
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]);
}
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
jq
Adapted from Wren
Works with gojq, the Go implementation of jq
The following uses some functions from the "bitwise" module. If, for example, your jq does not support modules, you could insert the relevant definitions therefrom in place of the "include" directive.
include "bitwise" {search: "."}; # see above
def Const: 6364136223846793005;
def Mask64: 18446744073709551615; # i.e. (1 | leftshift(64)) - 1
def Mask32: 4294967295; # i.e. (1 | leftshift(32)) - 1
# An initialization function if you do not wish to use seed/2
def rcg32:
{state: 9600629759793949339, # 0x853c49e6748fea9b
inc: 15726070495360670683 # 0xda3e39cb94b95bdb
};
# Input: {state, inc}
# Output: {state, inc, nextInt}
def nextInt:
.state as $old
| .state = bitwise_and($old * Const + .inc; Mask64)
| bitwise_and(( bitwise_xor($old | rightshift(18); $old) | rightshift(27)); Mask32) as $xorshifted
| bitwise_and($old|rightshift(59) ; Mask32) as $rot
| .nextInt = bitwise_and(
bitwise_or(
$xorshifted | rightshift($rot) ;
$xorshifted | leftshift( bitwise_and( 32 - $rot; 31) )) ;
Mask32) ;
def nextFloat:
nextInt
| .nextFloat = .nextInt / pow(2;32);
def seed($seedState; $seedSequence):
{state: 0,
inc: bitwise_and( bitwise_xor($seedSequence|leftshift(1); 1); Mask64)
}
| nextInt
| .state += $seedState
| nextInt;
def task1($n):
foreach range(0; $n) as $i (seed(42; 54); nextInt)
| .nextInt;
def task2($n):
reduce range(0; $n) as $i (seed(987654321; 1);
nextFloat
| .counts[((.nextFloat * 5)|floor)] += 1)
| "\nThe counts for \($n) repetitions are:",
(range(0; 5) as $i | "\($i) : \(.counts[$i])") ;
task1(5),
task2(100000)
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
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()
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 [20049, 20022, 20115, 19809, 20005] 0: 20049 1: 20022 2: 20115 3: 19809 4: 20005
Kotlin
Requires the experimental unsigned feature for integer types
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))
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
Lua
function uint32(n)
return n & 0xffffffff
end
function uint64(n)
return n & 0xffffffffffffffff
end
N = 6364136223846793005
state = 0x853c49e6748fea9b
inc = 0xda3e39cb94b95bdb
function pcg32_seed(seed_state, seed_sequence)
state = 0
inc = (seed_sequence << 1) | 1
pcg32_int()
state = state + seed_state
pcg32_int()
end
function pcg32_int()
local old = state
state = uint64(old * N + inc)
local shifted = uint32(((old >> 18) ~ old) >> 27)
local rot = uint32(old >> 59)
return uint32((shifted >> rot) | (shifted << ((~rot + 1) & 31)))
end
function pcg32_float()
return 1.0 * pcg32_int() / (1 << 32)
end
-------------------------------------------------------------------
pcg32_seed(42, 54)
print(pcg32_int())
print(pcg32_int())
print(pcg32_int())
print(pcg32_int())
print(pcg32_int())
print()
counts = { 0, 0, 0, 0, 0 }
pcg32_seed(987654321, 1)
for i=1,100000 do
local j = math.floor(pcg32_float() * 5.0) + 1
counts[j] = counts[j] + 1
end
print("The counts for 100,000 repetitions are:")
for i=1,5 do
print(" " .. (i - 1) .. ": " .. counts[i])
end
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0: 20049 1: 20022 2: 20115 3: 19809 4: 20005
Mathematica /Wolfram Language
ClearAll["Global`*"];
(*Constants*)
mask32 = BitAnd[2^32 - 1];
CONST = 6364136223846793005;
(*Convert Hex String to Expression*)
Hex[x_?StringQ] := ToExpression["16^^" <> StringDrop[x, 2]];
(*Definition of PCG32 Structure*)
PCG32[state_: Hex["0x853c49e6748fea9b"],
inc_: Hex["0xda3e39cb94b95bdb"]] := <|"state" -> state,
"inc" -> inc|>;
(*Function to generate next integer*)
nextInt[pcg_Association] :=
Module[{old, xorshifted, rot, newState}, old = pcg["state"];
newState = BitAnd[(old*CONST + pcg["inc"]), 2^64 - 1];
xorshifted =
BitAnd[BitShiftRight[BitXor[BitShiftRight[old, 18], old], 27],
mask32];
rot = BitAnd[BitShiftRight[old, 59], mask32];
<|"state" -> newState, "inc" -> pcg["inc"],
"nextInt" ->
BitAnd[BitOr[BitShiftRight[xorshifted, rot],
BitShiftLeft[xorshifted, BitAnd[-rot, 31]]], mask32]|>];
(*Function to generate next float*)
nextFloat[pcg_Association] := nextInt[pcg]["nextInt"]/2^32;
(*Function to seed the generator*)
seed[pcg_Association, st_, seq_] :=
Module[{newPcg},
newPcg = <|"state" -> 0,
"inc" -> BitOr[BitShiftLeft[seq, 1], 1]|>;
newPcg = nextInt[newPcg];
<|"state" -> newPcg["state"] + st, "inc" -> newPcg["inc"]|>];
(*Test function*)
testPCG32[] :=
Module[{randomGen, hist, n, nextGen}, randomGen = PCG32[];
randomGen = seed[randomGen, 42, 54];
Do[
nextGen = nextInt[randomGen];
randNumber = nextGen["nextInt"];
If[randNumber != 0, Print[randNumber]];
randomGen = nextGen
, {6}];
randomGen = seed[randomGen, 987654321, 1];
hist = ConstantArray[0, 5];
Do[nextGen = nextInt[randomGen];
hist[[Floor[nextFloat[nextGen]*5] + 1]] += 1;
randomGen = nextGen, {100000}];
Print[hist];
Do[Print[n - 1, ": ", hist[[n]], " "], {n, 1, 5}];];
(*Run the test*)
testPCG32[];
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 {20049, 20022, 20115, 19809, 20005} 0: 20049 1: 20022 2: 20115 3: 19809 4: 20005
Nim
import algorithm, sequtils, strutils, tables
const N = 6364136223846793005u64
type PCG32 = object
inc: uint64
state: uint64
func seed(gen: var PCG32; seedState, seedSequence: uint64) =
gen.inc = seedSequence shl 1 or 1
gen.state = (gen.inc + seedState) * N + gen.inc
func nextInt(gen: var PCG32): uint32 =
let xs = uint32((gen.state shr 18 xor gen.state) shr 27)
let rot = int32(gen.state shr 59)
result = uint32(xs shr rot or xs shl (-rot and 31))
gen.state = gen.state * N + gen.inc
func nextFloat(gen: var PCG32): float =
gen.nextInt().float / float(0xFFFFFFFFu32)
when isMainModule:
var gen: PCG32
gen.seed(42, 54)
for _ in 1..5:
echo gen.nextInt()
echo ""
gen.seed(987654321, 1)
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(", ")
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005
OCaml
let (>>) = Int64.shift_right_logical
let int32_bound n x =
Int64.(to_int ((mul (logand (of_int32 x) 0xffffffffL) (of_int n)) >> 32))
let int32_rotate_right x n =
Int32.(logor (shift_left x (-n land 31)) (shift_right_logical x n))
let pcg32_next inc st =
Int64.(add (mul st 0x5851f42d4c957f2dL) inc)
let pcg32_output st =
int32_rotate_right
(Int32.logxor (Int64.to_int32 (st >> 27)) (Int64.to_int32 (st >> 45)))
(Int64.to_int (st >> 59))
let seq_pcg32 (st, f) =
let rec repeat st () = Seq.Cons (pcg32_output st, repeat (f st)) in
repeat (f st)
let pcg32 seed_st seed_sq =
let inc = Int64.(add (succ seed_sq) seed_sq) in
Int64.add seed_st inc, pcg32_next inc
- Test:
let () =
pcg32 42L 54L |> seq_pcg32 |> Seq.take 5
|> Seq.iter (Printf.printf " %lu") |> print_newline
let () =
pcg32 987654321L 1L |> seq_pcg32 |> Seq.map (int32_bound 5) |> Seq.take 100000
|> Seq.fold_left (fun a n -> a.(n) <- succ a.(n); a) (Array.make 5 0)
|> Array.iteri (Printf.printf "%u: %u\n")
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0: 20049 1: 20022 2: 20115 3: 19809 4: 20005
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;
- 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)
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
- 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 than the above, and almost certainly slower, not that there is anywhere near enough work being done here to make that measureable.
with javascript_semantics include mpfr.e mpz cmult = 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)*cmult+inc,b64) mpz_add_ui(state,inc,seed_state) mpz_mul(state,state,cmult) 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,cmult) -- state += old*cmult 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^27) 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 l = and_bitsu(xorshifted << 32-rot, #FFFFFFFF), r = xorshifted >> rot, answer = xor_bitsu(l,r) 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 integer idx = floor(next_float()*5)+1 r[idx] += 1 end for ?r
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 {20049,20022,20115,19809,20005}
Python
Python: As class
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)
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 {0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005}
Python: As generator
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)
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 {0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005}
Raku
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.
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³² }
}
# 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;
# 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;
# 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;
- 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
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 coffees!
Numeric Digits 40
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
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=ishift(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
rb=left(copies('0',s)nb,length(nb))
rx=b2x(rb)
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
ishift: Procedure
/**********************************************************************
* Implement the shift operations for an int variable
* r = dshift(int,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,8)
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,8)
End
Else Do
If o='L' Then Do
rb=left(copies('0',s)nb,length(nb))
rx=b2x(rb)
r=x2d(rx,8)
End
Else Do
rb=left(copies(left(nb,1),s)nb,length(nb))
rx=b2x(rb)
r=x2d(rx,8)
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
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
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
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 {0=>20049, 1=>20022, 2=>20115, 3=>19809, 4=>20005}
Rust
struct PCG32 {
multiplier: u64,
state: u64,
inc: u64,
}
impl PCG32 {
fn new() -> Self {
PCG32 {
multiplier: 6364136223846793005,
state: 0x853c49e6748fea9b,
inc: 0xda3e39cb94b95bdb,
}
}
fn next_int(&mut self) -> u32 {
let old = self.state;
self.state = old.wrapping_mul(self.multiplier).wrapping_add(self.inc);
let xorshifted = (((old >> 18) ^ old) >> 27) as u32;
let rot = (old >> 59) as u32;
(xorshifted >> rot) | (xorshifted << ((!rot).wrapping_add(1) & 31))
}
fn next_float(&mut self) -> f64 {
(self.next_int() as f64) / ((1u64 << 32) as f64)
}
fn seed(&mut self, seed_state: u64, seed_sequence: u64) {
self.state = 0;
self.inc = (seed_sequence << 1) | 1;
self.next_int();
self.state = self.state.wrapping_add(seed_state);
self.next_int();
}
}
fn main() {
let mut rng = PCG32::new();
rng.seed(42, 54);
for _ in 0..5 {
println!("{}", rng.next_int());
}
println!();
let mut counts = [0; 5];
rng.seed(987654321, 1);
for _ in 0..100000 {
let j = (rng.next_float() * 5.0).floor() as usize;
counts[j] += 1;
}
println!("The counts for 100,000 repetitions are:");
for (i, count) in counts.iter().enumerate() {
println!(" {} : {}", i, count);
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
Scala
object PCG32 {
private val N = 6364136223846793005L
private var state = 0x853c49e6748fea9bL
private var inc = 0xda3e39cb94b95bdbL
def seed(seedState: Long, seedSequence: Long): Unit = {
state = 0
inc = (seedSequence << 1) | 1
nextInt()
state += seedState
nextInt()
}
def nextInt(): Int = {
val old = state
state = old * N + inc
val shifted = (((old >>> 18) ^ old) >>> 27).toInt
val rot = (old >>> 59).toInt
(shifted >>> rot) | (shifted << ((~rot + 1) & 31))
}
def nextFloat(): Double = {
val u = nextInt() & 0xffffffffL
u.toDouble / (1L << 32)
}
}
object Main extends App {
val r = PCG32
r.seed(42, 54)
println(Integer.toUnsignedString(r.nextInt()))
println(Integer.toUnsignedString(r.nextInt()))
println(Integer.toUnsignedString(r.nextInt()))
println(Integer.toUnsignedString(r.nextInt()))
println(Integer.toUnsignedString(r.nextInt()))
println()
val counts = Array(0, 0, 0, 0, 0)
r.seed(987654321, 1)
for (_ <- 1 to 100000) {
val j = Math.floor(r.nextFloat() * 5.0).toInt
counts(j) += 1
}
println("The counts for 100,000 repetitions are:")
for (i <- counts.indices) {
println(s" $i : ${counts(i)}")
}
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
Scheme
(import (scheme small) (srfi 33))
(define PCG-DEFAULT-MULTIPLIER 6364136223846793005)
(define MASK64 (- (arithmetic-shift 1 64) 1))
(define MASK32 (- (arithmetic-shift 1 32) 1))
(define-record-type <pcg32-random> (make-pcg32-random-record) pcg32?
(state pcg32-state pcg32-state!)
(inc pcg32-inc pcg32-inc!))
(define (make-pcg32)
(define rng (make-pcg32-random-record))
(pcg32-seed rng 31415926 535897932)
rng)
(define (pcg32-seed rng init-state init-seq)
(pcg32-state! rng 0)
(pcg32-inc! rng
(bitwise-and
(bitwise-ior (arithmetic-shift init-seq 1) 1)
MASK64))
(pcg32-next-int rng)
(pcg32-state! rng (bitwise-and (+ (pcg32-state rng) init-state) MASK64))
(pcg32-next-int rng))
(define (pcg32-next-int rng)
(define xorshifted 0)
(define rot 0)
(define answer 0)
(define oldstate (pcg32-state rng))
(pcg32-state! rng
(bitwise-and
(+ (* oldstate PCG-DEFAULT-MULTIPLIER) (pcg32-inc rng))
MASK64))
(set! xorshifted (bitwise-xor (arithmetic-shift oldstate -18) oldstate))
(set! xorshifted (arithmetic-shift xorshifted -27))
(set! xorshifted (bitwise-and xorshifted MASK32))
(set! rot (bitwise-and (arithmetic-shift oldstate -59) MASK32))
(set! answer (bitwise-ior
(arithmetic-shift xorshifted (- rot))
(arithmetic-shift xorshifted (bitwise-and (- rot) 31))))
(set! answer (bitwise-and answer MASK32))
answer)
(define (pcg32-next-float rng)
(inexact (/ (pcg32-next-int rng) (arithmetic-shift 1 32))))
;; task
(define rng (make-pcg32))
(pcg32-seed rng 42 54)
(let lp ((i 0)) (when (< i 5)
(display (pcg32-next-int rng))(newline)
(lp (+ i 1))))
(newline)
(pcg32-seed rng 987654321 1)
(define vec (make-vector 5 0))
(let lp ((i 0)) (when (< i 100000)
(let ((j (exact (floor (* (pcg32-next-float rng) 5)))))
(vector-set! vec j (+ (vector-ref vec j) 1)))
(lp (+ i 1))))
(let lp ((i 0)) (when (< i 5)
(display i)
(display " : ")
(display (vector-ref vec i))
(newline)
(lp (+ i 1))))
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
Sidef
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 }
- 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
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
- Test code:
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")
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0: 20049, 1: 20022, 2: 20115, 3: 19809, 4: 20005
Tcl
proc uint32 {n} {
return [expr {$n & 0xffffffff}]
}
proc uint64 {n} {
return [expr {$n & 0xffffffffffffffff}]
}
set N 6364136223846793005
set state 0x853c49e6748fea9b
set inc 0xda3e39cb94b95bdb
proc pcg32_seed {seed_state seed_sequence} {
global state inc
set state 0
set inc [expr {($seed_sequence << 1) | 1}]
pcg32_int
set state [expr {$state + $seed_state}]
pcg32_int
}
proc pcg32_int {} {
global state N inc
set old $state
set state [uint64 [expr {$old * $N + $inc}]]
set shifted [uint32 [expr {(($old >> 18) ^ $old) >> 27}]]
set rot [uint32 [expr {$old >> 59}]]
return [uint32 [expr {($shifted >> $rot) | ($shifted << ((~$rot + 1) & 31))}]]
}
proc pcg32_float {} {
return [expr {1.0 * [pcg32_int] / (1 << 32)}]
}
# -------------------------------------------------------------------
pcg32_seed 42 54
puts [pcg32_int]
puts [pcg32_int]
puts [pcg32_int]
puts [pcg32_int]
puts [pcg32_int]
puts ""
set counts {0 0 0 0 0}
pcg32_seed 987654321 1
for {set i 1} {$i <= 100000} {incr i} {
set j [expr {int([pcg32_float] * 5.0) + 1}]
lset counts [expr {$j - 1}] [expr {[lindex $counts [expr {$j - 1}]] + 1}]
}
puts "The counts for 100,000 repetitions are:"
foreach idx {0 1 2 3 4} {
puts " $idx: [lindex $counts $idx]"
}
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0: 20049 1: 20022 2: 20115 3: 19809 4: 20005
uBasic/4tH
uBasic/4tH only supports signed integers - so floating point is out of the question. It also requires clipping some integers to 32 bits in order to make this work.
' ** NOTE: this requires a 64-bit uBasic. **
If Info("wordsize") < 64 Then Print "This program requires a 64-bit uBasic" : End
n = 6364136223846793005
s = 377257722939173531 + 9223372036854775807 + 1
i = 6502698458505894875 + 9223372036854775807 + 1
Proc _PCG32Seed(42, 54);
Print FUNC(_PCG32Int)
Print FUNC(_PCG32Int)
Print FUNC(_PCG32Int)
Print FUNC(_PCG32Int)
Print FUNC(_PCG32Int)
End
_PCG32Int
Local (3)
a@ = s
s = (a@ * n) + i
b@ = And(Shl(Xor(Shl(a@, -18), a@), -27), 4294967295)
c@ = And(Shl(a@, -59), 4294967295)
Return (And(Or(Shl(b@, -c@), Shl(b@, And((Not(c@) + 1), 31))), 4294967295))
_PCG32Seed
Param (2)
s = 0
i = Or(Shl(b@, 1), 1)
Proc _PCG32Int
s = s + a@
Proc _PCG32Int
Return
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 0 OK, 0:391
Wren
As Wren doesn't have a 64-bit integer type, we use BigInt instead.
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])")
- Output:
2707161783 2068313097 3122475824 2211639955 3215226955 The counts for 100,000 repetitions are: 0 : 20049 1 : 20022 2 : 20115 3 : 19809 4 : 20005
- Programming Tasks
- Solutions by Programming Task
- 11l
- Ada
- ALGOL 68
- C
- C sharp
- C++
- D
- Dart
- Delphi
- System.SysUtils
- Velthuis.BigIntegers
- System.Generics.Collections
- F Sharp
- Factor
- FreeBASIC
- Go
- Haskell
- J
- Java
- Jq
- Julia
- Kotlin
- Lua
- Mathematica
- Wolfram Language
- Nim
- OCaml
- Perl
- Phix
- Python
- Raku
- REXX
- Ruby
- Rust
- Scala
- Scheme
- Sidef
- Standard ML
- Tcl
- UBasic/4tH
- Wren
- Wren-big