Pseudo-random numbers/PCG32: Difference between revisions
(Added Algol 68) |
No edit summary |
||
Line 28: | Line 28: | ||
:::E.g Binary 00110101 '''|''' Binary 00110011 == Binary 00110111 |
:::E.g Binary 00110101 '''|''' Binary 00110011 == Binary 00110111 |
||
The sequence of random numbers generated by the PCG32 algorithmn constitute a Markov chain. Those interested in an advanced exposition of Markov chains may wish to look here on RC. This is a simple example. There is a well known design pattern for generating Markov chains. The important thing to note is that element n depends only on element n-1. The algorithmn is given a start, in the case of random numbers known as the seed. To adhere to the first draft of this task the algorithmn will be given 2 U64 inputs called seed_state, and seed_sequence. The algorithmn proceeds in accordance with the following pseudocode:- |
|||
;[https://www.pcg-random.org/download.html#minimal-c-implementation| PCG32] Generator (pseudo-code): |
|||
<pre> |
|||
const N<-U64 6364136223846793005 |
|||
/* Let u64 denote an unsigned 64 bit integer type. */ |
|||
const inc<-U64 (seed_sequence << 1) | 1 |
|||
/* Let u32 denote an unsigned 32 bit integer type. */ |
|||
state<-U64 ((inc+seed_state)*N+inc |
|||
do forever |
|||
u64 global constant CONST = 6364136223846793005 |
|||
xs<-U32 (((state>>18)^state)>>27) |
|||
rot<-INT (state>>59) |
|||
class Pcg32 |
|||
OUTPUT U32 (xs>>rot)|(xs<<((-rot)&31)) |
|||
u64 instance variable state = HEX 853c49e6748fea9b |
|||
state<-state*N+inc |
|||
u64 instance variable inc = HEX da3e39cb94b95bdb /* Always odd */ |
|||
end do |
|||
</pre> |
|||
method seed(u64 seed_state, u64 seed_sequence) |
|||
This design pattern is so important that many modern languages will support this with a template called something like unfold. |
|||
state = 0 |
|||
inc = (seed_sequence << 1) | 1 # shift and | ensures its odd |
|||
next_int() |
|||
state = state + seed_state |
|||
next_int() |
|||
end method |
|||
method next_int() |
|||
u64 old = state |
|||
state = (old * CONST) + inc |
|||
u32 xorshifted = ((old >> 18) ^ old) >> 27 |
|||
u32 rot = old >> 59 |
|||
u32 answer = (xorshifted >> rot) | (xorshifted << ((-rot) & 31)) |
|||
return answer |
|||
end method |
|||
method next_float(): |
|||
return float next_int() / (1 << 32) |
|||
end method |
|||
end class |
|||
:; PCG32 Use: |
|||
random_gen = instance Pcg_32 |
|||
random_gen.seed(42, 54) |
|||
print(random_gen.next_int()) /* 2707161783 */ |
|||
print(random_gen.next_int()) /* 2068313097 */ |
|||
print(random_gen.next_int()) /* 3122475824 */ |
|||
print(random_gen.next_int()) /* 2211639955 */ |
|||
print(random_gen.next_int()) /* 3215226955 */ |
|||
;Task: |
;Task: |
||
* Generate a class/set of functions that generates pseudo-random |
* Generate a class/set of functions that generates pseudo-random |
||
numbers |
numbers using the above. |
||
* Show that the first five integers genrated with the seed <code>42, 54</code> |
* Show that the first five integers genrated with the seed <code>42, 54</code> |
||
are 2707161783 2068313097 3122475824 3215226955 |
|||
are as shown above |
|||
* Show that for an initial seed of <code>987654321, 1</code> the counts of 100_000 repetitions of |
* Show that for an initial seed of <code>987654321, 1</code> the counts of 100_000 repetitions of |
Revision as of 16:15, 15 August 2020
- 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
The sequence of random numbers generated by the PCG32 algorithmn constitute a Markov chain. Those interested in an advanced exposition of Markov chains may wish to look here on RC. This is a simple example. There is a well known design pattern for generating Markov chains. The important thing to note is that element n depends only on element n-1. The algorithmn is given a start, in the case of random numbers known as the seed. To adhere to the first draft of this task the algorithmn will be given 2 U64 inputs called seed_state, and seed_sequence. The algorithmn 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
This design pattern is so important that many modern languages will support this with a template called something like unfold.
- Task
- Generate a class/set of functions that generates pseudo-random
numbers using the above.
- Show that the first five integers genrated with the seed
42, 54
are 2707161783 2068313097 3122475824 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.
ALGOL 68
<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
Delphi
Velthuis.BigIntegers[1] by Rudy Velthuis.
<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
<lang factor>USING: accessors kernel locals math math.statistics prettyprint sequences ;
CONSTANT: mask64 0xffffffffffffffff CONSTANT: mask32 0xffffffff CONSTANT: const 6364136223846793005
TUPLE: pcg32 state inc ;
- <pcg32> ( -- pcg32 )
0x853c49e6748fea9b 0xda3e39cb94b95bdb pcg32 boa ;
- next-int ( pcg -- n )
pcg state>> :> old old const * pcg inc>> + mask64 bitand pcg state<< old -18 shift old bitxor -27 shift mask32 bitand :> shifted old -59 shift mask32 bitand :> r shifted r neg shift shifted r neg 31 bitand shift bitor mask32 bitand ;
- next-float ( pcg -- x ) next-int 1 32 shift /f ;
- seed ( pcg st seq -- )
0x0 pcg state<< seq 0x1 shift 1 bitor mask64 bitand 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
<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
Julia
<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
Phix
Phix proudly does not support the kind of "maths" whereby 255 plus 1 is 0 (or 127+1 is -128).
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
<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}
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.
<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³² }
}
- 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;</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
Wren
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