Pseudo-random numbers/Splitmix64
You are encouraged to solve this task according to the task description, using any language you may know.
Splitmix64 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.
Splitmix64 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" splitmix64 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. */ 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 */ } next_float() { return 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 splitmix64.
- Show the first five integers generated using the seed 1234567.
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821
- Show that for an initial seed of 987654321, the counts of 100_000 repetitions of
floor next_float() * 5
is as follows:
0: 20027, 1: 19892, 2: 20073, 3: 19978, 4: 20030
- Show your output here, on this page.
- See also
- Related tasks
11l
<lang 11l>T Splitmix64
UInt64 state
F seed(seed_state) .state = seed_state
F next_int() .state += 9E37'79B9'7F4A'7C15 V z = .state z = (z (+) (z >> 30)) * BF58'476D'1CE4'E5B9 z = (z (+) (z >> 27)) * 94D0'49BB'1331'11EB R z (+) (z >> 31)
F next_float() R Float(.next_int()) / 2.0^64
V random_gen = Splitmix64() random_gen.seed(1234567) L 5
print(random_gen.next_int())
random_gen.seed(987654321) V hist = Dict(0.<5, i -> (i, 0)) L 100'000
hist[Int(random_gen.next_float() * 5)]++
print(hist)</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 [0 = 20027, 1 = 19892, 2 = 20073, 3 = 19978, 4 = 20030]
Ada
Ada conversion of Next_float * 5.0 to an integer value resulted in some values of 5 which would have caused a buffer overflow in the counting array. The fix was to truncate Next_float * 5.0 as a floating point value and convert that value to an integer. Upon doing this the counts of each array element become 20073, indicating there are an equal number values in each portion of the random number range.
The random number functions are written in a stand-alone package. The package is split into a package specification defining the interfaces to the public subprograms and a body containing the implementation of the random number generator.
package specification: <lang Ada>with Interfaces; use Interfaces;
package Random_Splitmix64 is
function next_Int return Unsigned_64; function next_float return Float; procedure Set_State (Seed : in Unsigned_64);
end Random_Splitmix64;</lang> package body: <lang Ada>package body Random_Splitmix64 is
Internal : Unsigned_64 := 1234567;
-------------- -- next_Int -- --------------
function next_Int return Unsigned_64 is Z : Unsigned_64; begin Internal := Internal + 16#9e3779b97f4a7c15#; Z := Internal; Z := (Z xor Shift_Right(Z, 30)) * 16#bf58476d1ce4e5b9#; Z := (Z xor Shift_Right(Z, 27)) * 16#94d049bb133111eb#; return Z xor Shift_Right(Z, 31); end next_Int;
---------------- -- next_float -- ----------------
function next_float return Float is begin return float(next_int) / (2.0 ** 64); end next_float;
--------------- -- Set_State -- ---------------
procedure Set_State (Seed : in Unsigned_64) is begin Internal := Seed; end Set_State;
end Random_Splitmix64;</lang> Main procedure: <lang Ada>with Interfaces; use Interfaces; with Random_Splitmix64; use Random_Splitmix64; with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
subtype idx is Integer range 0 .. 4; type answer_arr is array (idx) of Unsigned_64; Vec : answer_arr := (others => 0); J : idx; fj : Float;
begin
Set_State (1_234_567); for I in 1 .. 5 loop Put (Unsigned_64'Image (next_Int)); New_Line; end loop;
Set_State (987_654_321);
for I in 1 .. 100_000 loop fj := Float'Truncation (next_float * 5.0); J := idx (fj); Vec (J) := Vec (J) + 1; end loop;
for I in Vec'Range loop Put_Line (I'Image & ":" & Unsigned_64'Image (Vec (J))); end loop;
end Main;</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 0: 20073 1: 20073 2: 20073 3: 20073 4: 20073
ALGOL 68
<lang algol68>BEGIN # generate some pseudo random numbers using Splitmix64 #
# note that although LONG INT is 64 bits in Algol 68G, LONG BITS is longer than 64 bits # LONG BITS mask 64 = LONG 16rffffffffffffffff; LONG BITS state := 16r1234567; LONG INT one shl 64 = ABS ( LONG 16r1 SHL 64 ); # sets the state to the specified seed value # PROC seed = ( LONG INT num )VOID: state := BIN num; # 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; # add a LONG BITS value to a LONG BITS # OP +:= = ( REF LONG BITS r, LONG BITS v )REF LONG BITS: r := SHORTEN ( BIN ( LENG ABS r + LENG ABS v ) AND mask 64 ); # multiplies a LONG BITS value by a LONG BITS value # OP *:= = ( REF LONG BITS r, LONG BITS v )REF LONG BITS: r := SHORTEN ( BIN ( ABS LENG r * LENG ABS v ) AND mask 64 ); # gets the next pseudo random integer # PROC next int = LONG INT: BEGIN state +:= LONG 16r9e3779b97f4a7c15; LONG BITS z := state; z XORAB ( z SHR 30 ); z *:= LONG 16rbf58476d1ce4e5b9; z XORAB ( z SHR 27 ); z *:= LONG 16r94d049bb133111eb; z XORAB ( z SHR 31 ); ABS z END # next int # ; # gets the next pseudo random real # PROC next float = LONG REAL: next int / one shl 64; BEGIN # task test cases # seed( 1234567 ); print( ( whole( next int, 0 ), newline ) ); # 6457827717110365317 # print( ( whole( next int, 0 ), newline ) ); # 3203168211198807973 # print( ( whole( next int, 0 ), newline ) ); # 9817491932198370423 # print( ( whole( next int, 0 ), newline ) ); # 4593380528125082431 # print( ( whole( next int, 0 ), newline ) ); # 16408922859458223821 # # count the number of occurances of 0..4 in a sequence of pseudo random reals scaled to be in [0..5) # seed( 987654321 ); [ 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:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 0: 20027 1: 19892 2: 20073 3: 19978 4: 20030
C
Code copied from the reference C implementation used by Java, and using GNU GCC v7.1.1. <lang c>/* Written in 2015 by Sebastiano Vigna (vigna@acm.org)
To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>. */
- include <stdint.h>
- include <stdio.h>
- include <math.h>
/* This is a fixed-increment version of Java 8's SplittableRandom generator
See http://dx.doi.org/10.1145/2714064.2660195 and http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
It is a very fast generator passing BigCrush, and it can be useful if for some reason you absolutely want 64 bits of state. */
static uint64_t x; /* The state can be seeded with any value. */
uint64_t next() { uint64_t z = (x += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31); }
double next_float() {
return next() / pow(2.0, 64);
}
int main() {
int i, j; x = 1234567; for(i = 0; i < 5; ++i) printf("%llu\n", next()); /* needed to use %lu verb for GCC 7.5.0-3 */ x = 987654321; int vec5[5] = {0, 0, 0, 0, 0}; for(i = 0; i < 100000; ++i) { j = next_float() * 5.0; vec5[j] += 1; } for(i = 0; i < 5; ++i) printf("%d: %d ", i, vec5[i]);
}
</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 0: 20027 1: 19892 2: 20073 3: 19978 4: 20030
Factor
<lang factor>USING: io kernel math math.bitwise math.functions math.statistics namespaces prettyprint sequences ;
SYMBOL: state
- seed ( n -- ) 64 bits state set ;
- next-int ( -- n )
0x9e3779b97f4a7c15 state [ + 64 bits ] change state get -30 0xbf58476d1ce4e5b9 -27 0x94d049bb133111eb -31 1 [ [ dupd shift bitxor ] dip * 64 bits ] 2tri@ ;
- next-float ( -- x ) next-int 64 2^ /f ;
! Test next-int "Seed: 1234567; first five integer values" print 1234567 seed 5 [ next-int . ] times nl
! Test next-float "Seed: 987654321; first 100,000 float values histogram" print 987654321 seed 100,000 [ next-float 5 * >integer ] replicate histogram .</lang>
- Output:
Seed: 1234567; first five integer values 6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 Seed: 987654321; first 100,000 float values histogram H{ { 0 20027 } { 1 19892 } { 2 20073 } { 3 19978 } { 4 20030 } }
Forth
<lang forth>variable rnd-state
- rnd-base-op ( z factor shift -- u ) 2 pick swap rshift rot xor * ;
- rnd-next ( -- u )
$9e3779b97f4a7c15 rnd-state +! rnd-state @ $bf58476d1ce4e5b9 #30 rnd-base-op $94d049bb133111eb #27 rnd-base-op #1 #31 rnd-base-op
- 1234567 rnd-state !
cr rnd-next u. cr rnd-next u. cr rnd-next u. cr rnd-next u. cr rnd-next u. cr
- rnd-next-float ( -- f )
rnd-next 0 d>f 0 1 d>f f/
create counts 0 , 0 , 0 , 0 , 0 ,
- counts-fill
#987654321 rnd-state ! 100000 0 do rnd-next-float 5.0e0 f* f>d drop cells counts + dup @ 1+ swap ! loop
- counts-disp
5 0 do cr i . ': emit bl emit counts i cells + @ . loop cr
counts-fill counts-disp</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 0 : 20027 1 : 19892 2 : 20073 3 : 19978 4 : 20030 ok
F#
<lang fsharp>// Pure F# Implementation of SplitMix64 let a: uint64 = 0x9e3779b97f4a7c15UL
let nextInt (state: uint64) =
let newstate = state + (0x9e3779b97f4a7c15UL) let rand = newstate let rand = (rand ^^^ (rand >>> 30)) * 0xbf58476d1ce4e5b9UL let rand = (rand ^^^ (rand >>> 27)) * 0x94d049bb133111ebUL let rand = rand ^^^ (rand >>> 31) (rand, newstate)
let nextFloat (state: uint64) =
let (rand, newState) = nextInt state let randf = (rand / (1UL <<< 64)) |> float (randf, newState)
[<EntryPoint>] let main argv =
let state = 1234567UL let (first, state) = nextInt state let (second, state) = nextInt state let (third, state) = nextInt state let (fourth, state) = nextInt state let (fifth, state) = nextInt state printfn "%i" first printfn "%i" second printfn "%i" third printfn "%i" fourth printfn "%i" fifth 0</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821
Go
<lang Go>package main
import (
"fmt" "math"
)
type Splitmix64 struct{ state uint64 }
func Splitmix64New(state uint64) *Splitmix64 { return &Splitmix64{state} }
func (sm64 *Splitmix64) nextInt() uint64 {
sm64.state += 0x9e3779b97f4a7c15 z := sm64.state z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9 z = (z ^ (z >> 27)) * 0x94d049bb133111eb return z ^ (z >> 31)
}
func (sm64 *Splitmix64) nextFloat() float64 {
return float64(sm64.nextInt()) / (1 << 64)
}
func main() {
randomGen := Splitmix64New(1234567) for i := 0; i < 5; i++ { fmt.Println(randomGen.nextInt()) }
var counts [5]int randomGen = Splitmix64New(987654321) 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:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 The counts for 100,000 repetitions are: 0 : 20027 1 : 19892 2 : 20073 3 : 19978 4 : 20030
Haskell
<lang haskell>import Data.Bits import Data.Word import Data.List
next :: Word64 -> (Word64, Word64) next state = f4 $ state + 0x9e3779b97f4a7c15
where f1 z = (z `xor` (z `shiftR` 30)) * 0xbf58476d1ce4e5b9 f2 z = (z `xor` (z `shiftR` 27)) * 0x94d049bb133111eb f3 z = z `xor` (z `shiftR` 31) f4 s = ((f3 . f2 . f1) s, s)
randoms = unfoldr (pure . next)
toFloat n = fromIntegral n / (2^64 - 1)</lang>
λ> mapM_ print $ take 5 $ randoms 1234567 6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 λ> let hist = map length . group . sort λ> hist . take 100000 $ (floor . (*5) . toFloat) <$> (randoms 987654321) [20027,19892,20073,19978,20030]
Julia
<lang julia>const C1 = 0x9e3779b97f4a7c15 const C2 = 0xbf58476d1ce4e5b9 const C3 = 0x94d049bb133111eb
mutable struct Splitmix64
state::UInt
end
""" return random int between 0 and 2**64 """ function next_int(smx::Splitmix64)
z = smx.state = smx.state + C1 z = (z ⊻ (z >> 30)) * C2 z = (z ⊻ (z >> 27)) * C3 return z ⊻ (z >> 31)
end
""" return random float between 0 and 1 """ next_float(smx::Splitmix64) = next_int(smx) / one(Int128) << 64
function testSplitmix64()
random_gen = Splitmix64(1234567) for i in 1:5 println(next_int(random_gen)) end
random_gen = Splitmix64(987654321) hist = fill(0, 5) for _ in 1:100_000 hist[Int(floor(next_float(random_gen) * 5)) + 1] += 1 end foreach(n -> print(n - 1, ": ", hist[n], " "), 1:5)
end
testSplitmix64()
</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 0: 20027 1: 19892 2: 20073 3: 19978 4: 20030
Mathematica/Wolfram Language
<lang Mathematica>ClearAll[BitShiftLevelUint, MultiplyUint, GenerateRandomNumbers] BitShiftLevelUint[z_, n_] := BitShiftRight[z, n] MultiplyUint[z_, n_] := Mod[z n, 2^64] GenerateRandomNumbers[st_, n_] := Module[{state = st},
Table[ state += 16^^9e3779b97f4a7c15; state = Mod[state, 2^64]; z = state; z = MultiplyUint[BitXor[z, BitShiftLevelUint[z, 30]], 16^^bf58476d1ce4e5b9]; z = MultiplyUint[BitXor[z, BitShiftLevelUint[z, 27]], 16^^94d049bb133111eb]; Mod[BitXor[z, BitShiftLevelUint[z, 31]], 2^64] , {n} ] ]
GenerateRandomNumbers[1234567, 5] nums = GenerateRandomNumbers[987654321, 10^5]; KeySort[Counts[Floor[5 nums/N[2^64]]]]</lang>
- Output:
{6457827717110365317, 3203168211198807973, 9817491932198370423, 4593380528125082431, 16408922859458223821} <|0->20027, 1->19892, 2->20073, 3->19978, 4->20030|>
Nim
<lang Nim>import math, sequtils, strutils
const Two64 = 2.0^64
type Splitmix64 = object
state: uint64
func initSplitmix64(seed: uint64): Splitmix64 =
## Initialize a Splitmiax64 PRNG. Splitmix64(state: seed)
func nextInt(r: var Splitmix64): uint64 =
## Return the next pseudorandom integer (actually a uint64 value). r.state += 0x9e3779b97f4a7c15u var z = r.state z = (z xor z shr 30) * 0xbf58476d1ce4e5b9u z = (z xor z shr 27) * 0x94d049bb133111ebu result = z xor z shr 31
func nextFloat(r: var Splitmix64): float =
## Retunr the next pseudorandom float (between 0.0 and 1.0 excluded). r.nextInt().float / Two64
when isMainModule:
echo "Seed = 1234567:" var prng = initSplitmix64(1234567) for i in 1..5: echo i, ": ", ($prng.nextInt).align(20)
echo "\nSeed = 987654321:" var counts: array[0..4, int] prng = initSplitmix64(987654321) for _ in 1..100_000: inc counts[int(prng.nextFloat * 5)] echo toSeq(counts.pairs).mapIt(($it[0]) & ": " & ($it[1])).join(", "</lang>
- Output:
Seed = 1234567: 1: 6457827717110365317 2: 3203168211198807973 3: 9817491932198370423 4: 4593380528125082431 5: 16408922859458223821 Seed = 987654321: 0: 20027, 1: 19892, 2: 20073, 3: 19978, 4: 20030
Perl
<lang perl>use strict; use warnings; no warnings 'portable'; use feature 'say'; use Math::AnyNum qw(:overload);
package splitmix64 {
sub new { my ($class, %opt) = @_; bless {state => $opt{seed}}, $class; }
sub next_int { my ($self) = @_; my $next = $self->{state} = ($self->{state} + 0x9e3779b97f4a7c15) & (2**64 - 1); $next = ($next ^ ($next >> 30)) * 0xbf58476d1ce4e5b9 & (2**64 - 1); $next = ($next ^ ($next >> 27)) * 0x94d049bb133111eb & (2**64 - 1); ($next ^ ($next >> 31)) & (2**64 - 1); }
sub next_float { my ($self) = @_; $self->next_int / 2**64; }
}
say 'Seed: 1234567, first 5 values:'; my $rng = splitmix64->new(seed => 1234567); say $rng->next_int for 1 .. 5;
my %h; say "\nSeed: 987654321, values histogram:"; $rng = splitmix64->new(seed => 987654321); $h{int 5 * $rng->next_float}++ for 1 .. 100_000; say "$_ $h{$_}" for sort keys %h;</lang>
- Output:
Seed: 1234567, first 5 values: 6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 Seed: 987654321, values histogram: 0 20027 1 19892 2 20073 3 19978 4 20030
Phix
As per Pseudo-random_numbers/PCG32#Phix, resorting to mpfr/gmp
with javascript_semantics include mpfr.e mpz state = mpz_init(), shift = mpz_init("0x9e3779b97f4a7c15"), mult1 = mpz_init("0xbf58476d1ce4e5b9"), mult2 = mpz_init("0x94d049bb133111eb"), b64 = mpz_init("0x10000000000000000"), -- (truncate to 64 bits) tmp = mpz_init(), z = mpz_init() procedure seed(integer num) mpz_set_si(state,num) end procedure procedure next_int() mpz_add(state, state, shift) -- state += shift mpz_fdiv_r(state, state, b64) -- state := remainder(z,b64) mpz_set(z, state) -- z := state mpz_tdiv_q_2exp(tmp, z, 30) -- tmp := trunc(z/2^30) mpz_xor(z, z, tmp) -- z := xor_bits(z,tmp) mpz_mul(z, z, mult1) -- z *= mult1 mpz_fdiv_r(z, z, b64) -- z := remainder(z,b64) mpz_tdiv_q_2exp(tmp, z, 27) -- tmp := trunc(z/2^27) mpz_xor(z, z, tmp) -- z := xor_bits(z,tmp) mpz_mul(z, z, mult2) -- z *= mult2 mpz_fdiv_r(z, z, b64) -- z := remainder(z,b64) mpz_tdiv_q_2exp(tmp, z, 31) -- tmp := trunc(z/2^31) mpz_xor(z, z, tmp) -- z := xor_bits(z,tmp) -- (result left in z) end procedure function next_float() next_int() mpfr f = mpfr_init_set_z(z) mpfr_div_z(f, f, b64) return mpfr_get_d(f) end function seed(1234567) for i=1 to 5 do next_int() printf(1,"%s\n",mpz_get_str(z)) end for seed(987654321) sequence r = repeat(0,5) for i=1 to 100000 do integer rdx = floor(next_float()*5)+1 r[rdx] += 1 end for ?r
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 {20027,19892,20073,19978,20030}
Object Pascal
<lang Pascal> program splitmix64;
{$IF Defined(FPC)}{$MODE Delphi}{$ENDIF} {$INLINE ON} {$Q-}{$R-}
{
Written in 2015 by Sebastiano Vigna (vigna@acm.org) http://prng.di.unimi.it/splitmix64.c
Onject Pascal port written in 2020 by I. Kakoulidis
To the extent possible under law, the author has dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
See <http://creativecommons.org/publicdomain/zero/1.0/>.
}
{
This is a fixed-increment version of Java 8's SplittableRandom generator See http://dx.doi.org/10.1145/2714064.2660195 and http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
It is a very fast generator passing BigCrush, and it can be useful if for some reason you absolutely want 64 bits of state.
} uses Math;
type
TSplitMix64 = record state: UInt64; procedure Init(seed: UInt64); inline; function Next(): UInt64; inline; function NextFloat(): double; inline; end;
procedure TSplitMix64.Init(seed: UInt64); begin
state := seed;
end;
function TSplitMix64.Next(): UInt64; begin
state := state + UInt64($9e3779b97f4a7c15); Result := state; Result := (Result xor (Result shr 30)) * UInt64($bf58476d1ce4e5b9); Result := (Result xor (Result shr 27)) * UInt64($94d049bb133111eb); Result := Result xor (Result shr 31);
end;
function TSplitMix64.NextFloat(): Double; begin
Result := Next() / 18446744073709551616.0;
end;
var
r: TSplitMix64; i, j: Integer; vec: array[0..4] of Integer;
begin
j := 0; r.Init(1234567); for i := 0 to 4 do WriteLn(r.Next());
r.Init(987654321); for i := 0 to 99999 do begin j := Trunc(r.NextFloat() * 5.0); Inc(vec[j]); end;
for i := 0 to 4 do Write(i, ': ', vec[i], ' ');
end.
</lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 0: 20027 1: 19892 2: 20073 3: 19978 4: 20030
PicoLisp
<lang PicoLisp>(zero *Split) # global state
(de mod64 (N)
(& N `(hex "FFFFFFFFFFFFFFFF")) )
(de mod64+ (A B)
(mod64 (+ A B)) )
(de mod64* (A B)
(mod64 (* A B)) )
(de roundf (N) # rounds down
(/ N (** 10 *Scl)) )
(de nextSplit ()
(setq *Split (mod64+ *Split `(hex "9e3779b97f4a7c15"))) (let Z *Split (setq Z (mod64* `(hex "bf58476d1ce4e5b9") (x| Z (>> 30 Z))) Z (mod64* `(hex "94d049bb133111eb") (x| Z (>> 27 Z))) ) (x| Z (>> 31 Z)) ) )
(prinl "First 5 numbers:") (setq *Split 1234567) (do 5
(println (nextSplit)) )
(prinl "The counts for 100,000 repetitions are:") (scl 12) (off R) (setq *Split 987654321) (do 100000
(accu 'R (roundf (* 5 (*/ (nextSplit) 1.0 18446744073709551616))) 1 ) )
(mapc println (sort R))</lang>
- Output:
First 5 numbers: 6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 The counts for 100,000 repetitions are: (0 . 20027) (1 . 19892) (2 . 20073) (3 . 19978) (4 . 20030)
Python
<lang python>MASK64 = (1 << 64) - 1 C1 = 0x9e3779b97f4a7c15 C2 = 0xbf58476d1ce4e5b9 C3 = 0x94d049bb133111eb
class Splitmix64():
def __init__(self, seed=0): self.state = seed & MASK64
def seed(self, num): self.state = num & MASK64 def next_int(self): "return random int between 0 and 2**64" z = self.state = (self.state + C1) & MASK64 z = ((z ^ (z >> 30)) * C2) & MASK64 z = ((z ^ (z >> 27)) * C3) & MASK64 answer = (z ^ (z >> 31)) & MASK64
return answer def next_float(self): "return random float between 0 and 1" return self.next_int() / (1 << 64)
if __name__ == '__main__':
random_gen = Splitmix64() random_gen.seed(1234567) for i in range(5): print(random_gen.next_int()) random_gen.seed(987654321) 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:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 {0: 20027, 1: 19892, 2: 20073, 3: 19978, 4: 20030}
Raku
<lang perl6>class splitmix64 {
has $!state;
submethod BUILD ( Int :$seed where * >= 0 = 1 ) { $!state = $seed }
method next-int { my $next = $!state = ($!state + 0x9e3779b97f4a7c15) +& (2⁶⁴ - 1); $next = ($next +^ ($next +> 30)) * 0xbf58476d1ce4e5b9 +& (2⁶⁴ - 1); $next = ($next +^ ($next +> 27)) * 0x94d049bb133111eb +& (2⁶⁴ - 1); ($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 6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 Seed: 987654321; first 1e5 Rat values histogram Bag(0(20027) 1(19892) 2(20073) 3(19978) 4(20030))
REXX
<lang rexx>/*REXX program generates pseudo─random numbers using the split mix 64 bit method.*/ numeric digits 200 /*ensure enough decimal digs for mult. */ parse arg n reps pick seed1 seed2 . /*obtain optional arguments from the CL*/ if n== | n=="," then n= 5 /*Not specified? Then use the default.*/ if reps== | reps=="," then reps= 100000 /* " " " " " " */ if pick== | pick=="," then pick= 5 /* " " " " " " */ if seed1== | seed1=="," then seed1= 1234567 /* " " " " " " */ if seed2== | seed2=="," then seed2= 987654321 /* " " " " " " */ const.1= x2d( 9e3779b97f4a7c15 ) /*initialize 1st constant to be used. */ const.2= x2d('bf58476d1ce4e5b9') /* " 2nd " " " " */ const.3= x2d( 94d049bb133111eb ) /* " 3rd " " " " */ o.30= copies(0, 30) /*construct 30 bits of zeros. */ o.27= copies(0, 27) /* " 27 " " " */ o.31= copies(0, 31) /* " 31 " " " */ w= max(3, length(n) ) /*for aligning the left side of output.*/ state= seed1 /* " the state to seed #1. */
do j=1 for n if j==1 then do; say center('n', w) " pseudo─random number " say copies('═', w) " ════════════════════════════" end say right(j':', w)" " right(commas(next()), 27) /*display a random number*/ end /*j*/
say if reps==0 then exit 0 /*stick a fork in it, we're all done. */ say center('#', w) " count of pseudo─random #" say copies('═', w) " ════════════════════════════" state= seed2 /* " the state to seed #2. */ @.= 0; div= pick / 2**64 /*convert division to inverse multiply.*/
do k=1 for reps parse value next()*div with _ '.' /*get random #, floor of a "division". */ @._= @._ + 1 /*bump the counter for this random num.*/ end /*k*/
do #=0 for pick say right(#':', w)" " right(commas(@.#), 15) /*show count of a random num.*/ end /*#*/
exit 0 /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: parse arg _; do ?=length(_)-3 to 1 by -3; _= insert(',', _, ?); end; return _ b2d: parse arg ?; return x2d( b2x(?) ) /*convert bin──►decimal. */ d2b: parse arg ?; return right( x2b( d2x(?) ), 64, 0) /*convert dec──►64 bit bin.*/ /*──────────────────────────────────────────────────────────────────────────────────────*/ next: procedure expose state const. o.
state= state + const.1 ; z= d2b(state) /*add const1──►STATE; conv.*/ z= xor(z, left(o.30 || z, 64)); z= d2b(b2d(z)*const.2) /*shiftR 30 bits & XOR; " */ z= xor(z, left(o.27 || z, 64)); z= d2b(b2d(z)*const.3) /* " 27 " " " " */ z= xor(z, left(o.31 || z, 64)); return b2d(z) /* " 31 " " " " */
/*──────────────────────────────────────────────────────────────────────────────────────*/ xor: parse arg a, b; $= /*perform a bit─wise XOR. */
do !=1 for length(a); $= $ || (substr(a,!,1) && substr(b,!,1) ) end /*!*/; return $</lang>
- output when using the default inputs:
n pseudo─random number ═══ ════════════════════════════ 1: 6,457,827,717,110,365,317 2: 3,203,168,211,198,807,973 3: 9,817,491,932,198,370,423 4: 4,593,380,528,125,082,431 5: 16,408,922,859,458,223,821 # count of pseudo─random # ═══ ════════════════════════════ 0: 20,027 1: 19,892 2: 20,073 3: 19,978 4: 20,030
Ruby
<lang ruby>class Splitmix64
MASK64 = (1 << 64) - 1 C1, C2, C3 = 0x9e3779b97f4a7c15, 0xbf58476d1ce4e5b9, 0x94d049bb133111eb def initialize(seed = 0) = @state = seed & MASK64 def rand_i z = @state = (@state + C1) & MASK64 z = ((z ^ (z >> 30)) * C2) & MASK64 z = ((z ^ (z >> 27)) * C3) & MASK64 (z ^ (z >> 31)) & MASK64 end def rand_f = rand_i.fdiv(1<<64)
end
rand_gen = Splitmix64.new(1234567) 5.times{ puts rand_gen.rand_i }
rand_gen = Splitmix64.new(987654321) p 100_000.times.lazy.map{(rand_gen.rand_f * 5).floor}.tally.sort.to_h </lang>
- Output:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 {0=>20027, 1=>19892, 2=>20073, 3=>19978, 4=>20030}
Sidef
<lang ruby>class Splitmix64(state) {
define ( mask64 = (2**64 - 1) )
method next_int { var n = (state = ((state + 0x9e3779b97f4a7c15) & mask64)) n = ((n ^ (n >> 30)) * 0xbf58476d1ce4e5b9 & mask64) n = ((n ^ (n >> 27)) * 0x94d049bb133111eb & mask64) (n ^ (n >> 31)) & mask64 }
method next_float { self.next_int / (mask64+1) }
}
say 'Seed: 1234567, first 5 values:' var rng = Splitmix64(1234567) 5.of { rng.next_int.say }
say "\nSeed: 987654321, values histogram:" var rng = Splitmix64(987654321) var histogram = Bag(1e5.of { floor(5*rng.next_float) }...) histogram.pairs.sort.each { .join(": ").say }</lang>
- Output:
Seed: 1234567, first 5 values: 6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 Seed: 987654321, values histogram: 0: 20027 1: 19892 2: 20073 3: 19978 4: 20030
Wren
No 64 bit integers so we use BigInt with a mask. <lang ecmascript>import "/big" for BigInt
var Const1 = BigInt.fromBaseString("9e3779b97f4a7c15", 16) var Const2 = BigInt.fromBaseString("bf58476d1ce4e5b9", 16) var Const3 = BigInt.fromBaseString("94d049bb133111eb", 16) var Mask64 = (BigInt.one << 64) - BigInt.one
class Splitmix64 {
construct new(state) { _state = state }
nextInt { _state = (_state + Const1) & Mask64 var z = _state z = ((z ^ (z >> 30)) * Const2) & Mask64 z = ((z ^ (z >> 27)) * Const3) & Mask64 return (z ^ (z >> 31)) & Mask64 }
nextFloat { nextInt.toNum / 2.pow(64) }
}
var randomGen = Splitmix64.new(BigInt.new(1234567)) for (i in 0..4) System.print(randomGen.nextInt)
var counts = List.filled(5, 0) randomGen = Splitmix64.new(BigInt.new(987654321)) 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:
6457827717110365317 3203168211198807973 9817491932198370423 4593380528125082431 16408922859458223821 The counts for 100,000 repetitions are: 0 : 20027 1 : 19892 2 : 20073 3 : 19978 4 : 20030