123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309(**************************************************************************)(* *)(* OCaml *)(* *)(* Damien Doligez, projet Para, INRIA Rocquencourt *)(* Xavier Leroy, projet Cambium, College de France and Inria *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)(* Pseudo-random number generator *)externalrandom_seed:unit->intarray="caml_sys_random_seed"moduleState=structopenBigarraytypet=(int64,int64_elt,c_layout)Array1.texternalnext:t->(int64[@unboxed])="caml_lxm_next""caml_lxm_next_unboxed"[@@noalloc]letcreate():t=Array1.createInt64C_layout4letsetsi1i2i3i4=Array1.unsafe_sets0(Int64.logori11L);(* must be odd *)Array1.unsafe_sets1i2;Array1.unsafe_sets2(ifi3<>0Ltheni3else1L);(* must not be 0 *)Array1.unsafe_sets3(ifi4<>0Ltheni4else2L)(* must not be 0 *)letmki1i2i3i4=lets=create ()insetsi1i2i3i4;sletserialization_prefix="lxm1:"(* "lxm" denotes the algorithm currently in use, and '1' is
a version number. We should update this prefix if we change
the Random algorithm or the serialization format, so that users
get a clean error instead of believing that they faithfully
reproduce their previous state and in fact get a differrent
stream.
Note that there is no constraint to keep the same
"<name><ver>:<data>" format or message size in future versions,
we could change the format completely if we wanted as long
as there is no confusion possible with the previous formats. *)letserialization_prefix_len=String.lengthserialization_prefixletto_binary_strings=letprefix=serialization_prefix inletpreflen=serialization_prefix_leninletbuf=Bytes.create(preflen+4*8)inBytes.blit_stringprefix0buf0preflen;fori=0to3doBytes.set_int64_lebuf(preflen+i*8)(Array1.getsi)done;Bytes.unsafe_to_stringbuf(* Compatibility functions Imported from standard library *)#ifOCAML_VERSION<(4,8,0)letset_int64_leboffn=letn=refninfori=0to 7doBytes.setb(off+i)Int64.(Char.unsafe_chr@@Int64.to_int@@logand!n0xFFL);n:=Int64.(shift_right!n8)done#elseletset_int64_le=Bytes.set_int64_le#endif#ifOCAML_VERSION<(4,13,0)letget_int64_le soff=letres=refInt64.zeroinfori=7downto0doletv=Int64.of_int(Char.code s.[off+i])inres :=Int64.(addv(shift_left!res8))done;!resletstarts_with~prefixs=letopenStringinletlen_s=length sandlen_pre=lengthprefixinletrecauxi=if i=len_pre thentrueelseifunsafe_getsi<>unsafe_getprefixithenfalseelseaux(i+1)inlen_s>=len_pre&&aux0#elseletget_int64_le=String.get_int64_leletstarts_with=String.starts_with#endifletof_binary_stringbuf=letprefix=serialization_prefixinletpreflen=serialization_prefix_leninifString.lengthbuf<>preflen+4*8||not(starts_with~prefixbuf)thenfailwith("Random.State.of_binary_string: expected a format \
compatible with OCaml "^Sys.ocaml_version);leti1=get_int64_lebuf(preflen+0*8)inleti2=get_int64_le buf(preflen+1*8)inleti3=get_int64_lebuf(preflen+2*8)inleti4=get_int64_lebuf(preflen+3*8)inmki1i2i3i4letassign(dst:t)(src:t)=Array1.blitsrcdstletcopys=lets' =create()inassigns's;s'(* The seed is an array of integers. It can be just one integer,
but it can also be 12 or more bytes. To hide the difference,
we serialize the array as a sequence of bytes, then hash the
sequence with MD5 (Digest.bytes). MD5 gives only 128 bits while
we need 256 bits, sowe hash twice with different suffixes. *)letreinitsseed=letn=Array.lengthseedinletb=Bytes.create(n*8+1)infori=0ton-1doset_int64_leb(i*8)(Int64.of_intseed.(i))done;Bytes.setb(n*8)'\x01';let d1=Digest.bytesbinBytes.set b(n*8)'\x02';letd2=Digest.bytesbinsets(get_int64_led10)(get_int64_led18)(get_int64_led20)(get_int64_led28)letmakeseed=lets=create()inreinitsseed;sletmake_self_init()=make(random_seed())(* Return30random bits as an integer 0<= x < 1073741824*)letbitss=Int64.to_int(nexts)land0x3FFF_FFFF(* Return an integer between 0 (included) and [bound] (excluded) *)letrecintauxsn=letr=bitssinletv=rmodninifr-v>0x3FFFFFFF-n+1thenintauxsnelsevletintsbound=ifbound>0x3FFFFFFF||bound<=0theninvalid_arg"Random.int"elseintauxsbound(* Return an integer between 0 (included)and [bound] (excluded).[bound] may be anypositive [int]. *)letrecint63auxsn=letr=Int64.to_int(nexts)landmax_intinletv=rmodninifr-v>max_int-n+1thenint63auxsnelsevletfull_intsbound=ifbound<=0theninvalid_arg"Random.full_int"elseifbound>0x3FFFFFFFthenint63auxsboundelseintauxsbound(* Return32 random bits as an [int32]*)letbits32s=Int64.to_int32(nexts)(* Return an [int32] between 0 (included) and [bound] (excluded). *)letrecint32auxsn=let r=Int32.shift_right_logical(bits32s)1inletv=Int32.remrninifInt32.(subrv>add(submax_int n)1l)thenint32aux snelsevletint32sbound =ifbound<=0ltheninvalid_arg"Random.int32"elseint32auxsbound(* Return 64 random bits as an [int64] *)letbits64s=nexts(* Return an [int64] between 0 (included) and [bound] (excluded). *)letrecint64auxsn=letr=Int64.shift_right_logical(bits64s)1inletv=Int64.remrninifInt64.(subrv>add(submax_intn)1L)thenint64auxsnelsevletint64sbound=ifbound<=0Ltheninvalid_arg"Random.int64"elseint64auxsbound(*Return 32 or 64 random bitsas a [nativeint] *)letnativebits=ifNativeint.size=32thenfuns->Nativeint.of_int32(bits32s)elsefuns->Int64.to_nativeint(bits64s)(* Return a [nativeint] between 0 (included) and [bound] (excluded).*)letnativeint=ifNativeint.size=32thenfunsbound->Nativeint.of_int32(int32s(Nativeint.to_int32 bound))elsefunsbound->Int64.to_nativeint(int64s(Int64.of_nativeintbound))(* Return a float 0 < x < 1 uniformly distributed among the
multiples of 2^-53 *)letrecrawfloats=letb=nextsinletn=Int64.shift_right_logicalb11inifn<>0LthenInt64.to_floatn*.0x1.p-53elserawfloats(* Return a float between 0 and [bound] *)letfloatsbound =rawfloats*.bound(* Return a random Boolean *)letbools=nexts<0L(* Split a new PRNG off the given PRNG *)let splits=leti1=bits64 sinleti2=bits64sinleti3 =bits64sinleti4=bits64sinmki1i2i3i4endletmk_default()=(* This is the state obtained with [State.make [| 314159265 |]]. *)State.mk(-6196874289567705097L)586573249833713189L(-8591268803865043407L)6388613595849772044L#ifOCAML_VERSION<(5,0,0)letrandom_key=mk_default()letbits()=State.bitsrandom_keyletintbound=State.intrandom_keyboundletfull_intbound=State.full_intrandom_keyboundletint32bound=State.int32random_keyboundletnativeintbound=State.nativeintrandom_keyboundletint64bound=State.int64random_keyboundletfloatscale=State.floatrandom_keyscaleletbool()=State.boolrandom_keyletbits32()=State.bits32random_keyletbits64()=State.bits64random_keyletnativebits()=State.nativebitsrandom_keyletfull_initseed=State.reinitrandom_keyseedletinitseed=full_init[|seed|]letself_init()=full_init(random_seed())(* Splitting *)letsplit()=State.splitrandom_key(* Manipulating the current state. *)letget_state()=State.copyrandom_keyletset_states=State.assignrandom_keys#elseletrandom_key=Domain.DLS.new_key~split_from_parent:State.splitmk_defaultletbits()=State.bits(Domain.DLS.getrandom_key)letintbound=State.int(Domain.DLS.getrandom_key)boundletfull_intbound=State.full_int(Domain.DLS.getrandom_key)boundletint32bound=State.int32(Domain.DLS.getrandom_key)boundletnativeintbound=State.nativeint(Domain.DLS.getrandom_key)boundletint64bound=State.int64(Domain.DLS.getrandom_key)boundletfloatscale=State.float(Domain.DLS.getrandom_key)scaleletbool()=State.bool(Domain.DLS.getrandom_key)letbits32()=State.bits32(Domain.DLS.getrandom_key)letbits64()=State.bits64(Domain.DLS.getrandom_key)letnativebits()=State.nativebits(Domain.DLS.getrandom_key)letfull_initseed=State.reinit(Domain.DLS.getrandom_key)seedletinitseed=full_init[|seed|]letself_init()=full_init(random_seed())(* Splitting *)letsplit()=State.split(Domain.DLS.getrandom_key)(* Manipulating the current state. *)letget_state()=State.copy(Domain.DLS.getrandom_key)letset_states=State.assign(Domain.DLS.getrandom_key)s#endif