Pseudo-random numbers/Splitmix64
Shiftmix64 is the default pseudo-random number generator algorithm in Java and is included / available in many other languages. It uses a fairly simple algorithm that, though it is considered to be poor for cryptographic purposes, is very fast to calculate, and is "good enough" for many random number needs. It passes several fairly rigorous PRNG "fitness" tests that some more complex algorithms fail.
Shiftmix64 is not recommended for demanding random number requirements, but is often used to calculate initial states for other more complex pseudo-random number generators.
The "standard" shiftmix64 maintains one 64 bit state variable and returns 64 bits of random data with each call.
Basic pseudocode algorithm:
uint64 state /* The state can be seeded with any (upto) 64 bit integer value. */ uint64 next-int() { state += 0x9e3779b97f4a7c15 /* increment the state variable */ uint64 z = state /* copy the state to a working variable */ z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9 /* xor the variable with the variable right bit shifted 30 then multiply by a constant */ z = (z ^ (z >> 27)) * 0x94d049bb133111eb /* xor the variable with the variable right bit shifted 27 then multiply by a constant */ return z ^ (z >> 31) /* return the variable xored with itself right bit shifted 31 */ } uint64 next-float() { return float next-int() / (1 << 64) /* divide by 2^64 to return a value between 0 and 1 */ }
The returned value should hold 64 bits of numeric data. If your language does not support unsigned 64 bit integers directly you may need to apply appropriate bitmasks during bitwise operations.
In keeping with the general layout of several recent pseudo-random number tasks:
- Task
- Write a class or set of functions that generates pseudo-random numbers using shiftmix64.
- Show the first five integers generated using the seed 1234567.
9086773575395155592 12075168200337577354 5360881288835356517 10975871416297420776 2494458855142162015
- Show that for an initial seed of 987654321, the counts of 100_000 repetitions of
floor next_float() * 5
is as follows:
0: 19929, 1: 19817, 2: 20085, 3: 20122, 4: 20047
- Show your output here, on this page.
- See also
- Related tasks
Raku
<lang perl6>class splitmix64 {
has $!state;
submethod BUILD ( Int :$seed where * >= 0 = 1 ) { $!state = $seed }
method next-int { my $next = $!state += 0x9e3779b97f4a7c15; $next +^= ($next +> 30) * 0xbf58476d1ce4e5b9; $next +^= ($next +> 27) * 0x94d049bb133111eb; ($next +^ ($next +> 31)) +& (2⁶⁴ - 1); }
method next-rat { self.next-int / 2⁶⁴ }
}
- Test next-int
say 'Seed: 1234567; first five Int values'; my $rng = splitmix64.new( :seed(1234567) ); .say for $rng.next-int xx 5;
- Test next-rat (since these are rational numbers by default)
say "\nSeed: 987654321; first 1e5 Rat values histogram"; $rng = splitmix64.new( :seed(987654321) ); say ( ($rng.next-rat * 5).floor xx 100_000 ).Bag;</lang>
- Output:
Seed: 1234567; first five Int values 9086773575395155592 12075168200337577354 5360881288835356517 10975871416297420776 2494458855142162015 Seed: 987654321; first 1e5 Rat values histogram Bag(0(19929) 1(19817) 2(20085) 3(20122) 4(20047)