1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768openStdintletmaxint32=Uint64.of_int0xffffffff(* [to_uint32 nxt s store] advances state [s] and optains a random uint64 integers
using function [nxt]. The resulting int is split into 2 uint32 integers where
one of them is returned to the caller while the next is put into [store]. If
[store] is not empty then the [nxt] is not called and the integer stored in
[store] is returned and an empty store is returned to the caller. A 3-tuple is
returned of the form: (new uint32, new state s, new store). *)letnext_uint32~nexts=function|Somex->x,s,None|None->letuint,s'=nextsinUint64.(loganduintmaxint32|>to_uint32),s',SomeUint64.(shift_rightuint32|>to_uint32)(* [next_double nextu64 t] returns a random float from bitgenerator [t] using
function [nextu64] and a new bitgenerator with its internal state advanced forward by a step. *)letnext_double~nextu64t=matchnextu64twith|u,t'->Uint64.(shift_rightu11|>to_int)|>Float.of_int|>(*.)(1.0/.9007199254740992.0),t'(* Generate a random uint64 integer in the range [0, b) where [b] is the upper bound.
This implementation uses Lemire's method. See: https://arxiv.org/abs/1805.10941 *)letnext_bounded_uint64b~nextu64t=letb'=Uint128.of_uint64bandr=Uint64.(rem(negb)b)inletrecloop=function|m,swhenUint128.to_uint64m>=r->Uint128.(shift_rightm64|>to_uint64),s|_,s->matchnextu64swith|x,s'->loopUint128.(of_uint64x*b',s')inletx,t'=nextu64tinmatchUint128.(of_uint64x*b')with|mwhenUint128.(to_uint64m<b)->loop(m,t')|m->Uint128.(shift_rightm64|>to_uint64),t'moduletypeBITGEN=sigtypet(** [t] is the state of the bitgenerator. *)valnext_uint64:t->uint64*t(** [next_uint64 t] Generates a random unsigned 64-bit integer and a state
of the generator advanced forward by one step. *)valnext_uint32:t->uint32*t(** [next_uint32 t] Generates a random unsigned 32-bit integer and a state
of the generator advanced forward by one step. *)valnext_bounded_uint64:uint64->t->uint64*t(** [next_bounded_uint64 b t] Generates a random unsigned 64-bit integer
in the interval {m [0, b)}. It returns the integer as well as the state of the
generator advanced forward. To generate an integer in the range {m [a, b)},
one should generate an integer in {m [0, b - a)} using [next_bounded_uint64 (b - a) t]
and then add [a] to the resulting integer to get the output in the desired range. *)valnext_double:t->float*t(** [next_double t] Generates a random 64 bit float and a state of the
generator advanced forward by one step. *)valinitialize:Seed.SeedSequence.t->t(** [initialize s] Returns the initial state of the generator. The random stream
is determined by the initialization of the seed sequence [s] of {!SeedSequence.t} type. *)end