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.tletnext=Prng.nextletcreate():t=Array1.createInt64C_layout4letsetsi1i2i3i4=Array1.unsafe_sets0(Int64.logori11L);(*must be odd *)Array1.unsafe_sets1i2;Array1.unsafe_set s2(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_prefix(* Compatibility functions Imported from standard library *)#ifOCAML_VERSION<(4,8,0)letset_int64_leboffn=letn=refninfori=0to7doBytes.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_lesoff=letres=refInt64.zero infori=7downto0doletv=Int64.of_int(Char.codes.[off+i])inres:=Int64.(addv(shift_left!res8))done;!resletstarts_with~prefixs=letopenStringinlet len_s=lengthsand len_pre =lengthprefixinletrecauxi=ifi=len_prethentrueelseifunsafe_getsi<>unsafe_getprefixithenfalseelse aux(i+1)inlen_s >=len_pre&&aux0#elseletget_int64_le=String.get_int64_leletstarts_with=String.starts_with#endifletto_binary_strings=letprefix=serialization_prefixinletpreflen=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_stringbufletof_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,
weserialize the array asa sequence of bytes, then hash the
sequence with MD5 (Digest.bytes). MD5 gives only 128 bits while
we need 256 bits, so we hashtwice 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';letd1=Digest.bytesbinBytes.setb(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())(*Return 30 randombits as an integer0<= x <1073741824 *)letbitss=Int64.to_int(nexts)land0x3FFF_FFFF(* Return an integer between0 (included) and [bound] (excluded) *)letrecintauxsn=letr=bitssinletv=rmodninifr-v>0x3FFFFFFF-n+1thenintaux snelsevletintsbound=ifbound>0x3FFFFFFF||bound<=0theninvalid_arg"Random.int"elseintauxsbound(* Return an integer between 0 (included) and [bound] (excluded).
[bound]may be any positive [int]. *)letrecint63auxsn=letr=Int64.to_int (nexts)landmax_int inletv=rmodninifr-v>max_int-n+1then int63auxsnelsevletfull_intsbound=ifbound <=0theninvalid_arg"Random.full_int"elseifbound>0x3FFFFFFFthenint63auxsboundelseintauxsbound(* Return 32 random bits as an [int32] *)letbits32s=Int64.to_int32(next s)(* Return an [int32] between 0(included) and [bound] (excluded). *)letrecint32auxsn=letr=Int32.shift_right_logical(bits32s)1inletv=Int32.remrninifInt32.(subrv>add(submax_intn)1l)thenint32auxsnelsevletint32sbound=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(* Return32 or 64 random bits as 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_int32bound))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=next s<0L(* Split a new PRNG off the given PRNG *)letsplits=leti1=bits64sinlet i2=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_key boundletfull_intbound=State.full_intrandom_keyboundletint32bound=State.int32 random_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