123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255(**************************************************************************)(* *)(* 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;sletassign(dst:t)(src:t)=Array1.blitsrcdstletcopys=lets'=create()inassigns's;s'(* Compatibility functions *)#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.zeroinfori=7downto0doletv=Int64.of_int(Char.codes.[off+i])inres:=Int64.(addv(shift_left!res8))done;!res#elseletget_int64_le=String.get_int64_le#endif(* The seed isan array of integers. It can be just one integer,
but it canalso be 12 or more bytes. Tohide the difference,
we serialize 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 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';letd1=Digest.bytesbinBytes.setb(n*8)'\x02';let d2=Digest.bytesbinsets(get_int64_led10)(get_int64_led18)(get_int64_le d20)(get_int64_led28)letmakeseed=lets=create()inreinitsseed;sletmake_self_init()=make(random_seed())(*Return 30 random bits as an integer 0 <= x < 1073741824*)let bitss=Int64.to_int(nexts)land0x3FFF_FFFF(* Return an integer between 0 (included) and [bound] (excluded) *)letrecintauxsn=letr=bits sinlet v=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 any positive [int]. *)letrecint63auxsn=letr=Int64.to_int(nexts)landmax_intinletv=rmodninifr-v>max_int-n+1thenint63auxsnelsevletfull_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=next s(* 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 or64 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 float0 < 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 *)letsplits=leti1=bits64sinleti2=bits64 sinleti3=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.int32random_keyboundletnativeintbound=State.nativeintrandom_keyboundletint64bound=State.int64random_keyboundletfloatscale=State.float random_keyscaleletbool()=State.boolrandom_keyletbits32()=State.bits32random_keyletbits64()=State.bits64random_keyletnativebits()=State.nativebits random_keyletfull_initseed=State.reinitrandom_keyseedletinitseed=full_init[| seed|]letself_init()=full_init(random_seed())(* Splitting *)letsplit()=State.split random_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