123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256(**************************************************************************)(* *)(* 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;sletassign(dst:t)(src:t)=Array1.blitsrc dstletcopys=lets'=create()inassigns's;s'(* Compatibility functions *)#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_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 is an arrayof integers. It can bejust one integer,
but it can also be 12 or more bytes. To hide the difference,
we serialize the arrayas a sequence of bytes, then hash the
sequence with MD5 (Digest.bytes). MD5 gives only 128 bitswhile
weneed 256 bits, so we hash twice with different suffixes. *)letreinitsseed=letn=Array.lengthseedinletb=Bytes.create(n*8+1)infori=0ton-1doset_int64_le b(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 random bits as an integer 0 <= x < 1073741824 *)letbitss=Int64.to_int(nexts)land0x3FFF_FFFF(* Return an integer between 0 (included) and [bound] (excluded) *)letrecintauxsn=let r=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 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 >0x3FFFFFFF thenint63auxsboundelseintaux sbound(* Return 32 random bits as an [int32] *)letbits32s=Int64.to_int32(nexts)(* 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(* Return 32 or 64 random bitsas a [nativeint] *)letnativebits=ifNativeint.size=32thenfuns->Nativeint.of_int32(bits32s)elsefuns->Int64.to_nativeint(bits64s)(* Returna [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))(* Returna 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 *)letsplits=leti1=bits64sinleti2=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.int32random_keyboundletnativeintbound=State.nativeint random_keyboundletint64bound=State.int64random_key boundletfloatscale=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