PCG32

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

Last updated