123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390(***********************************************************************)(* *)(* Objective Caml *)(* *)(* Damien Doligez, projet Para, INRIA Rocquencourt *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. All rights reserved. This file is distributed *)(* under the terms of the GNU Library General Public License, with *)(* the special exception on linking described in file ../LICENSE. *)(* *)(***********************************************************************)(* "Linear feedback shift register" pseudo-random number generator. *)(* References: Robert Sedgewick, "Algorithms", Addison-Wesley *)(* The PRNG is a linear feedback shift register.
It is seeded by a MD5-based PRNG.
*)externalrandom_seed:unit->intarray="caml_sys_random_seed"moduleState=structtypet={st:intarray;mutableidx:int}letnew_state()={st=Array.make550;idx=0}letassign st1st2=Array.blitst2.st0st1.st055;st1.idx<-st2.idxletserialization_prefix="lfsr1:"(* "lfsr" denotes the algorithm currently in use, and '1' is
a version number. Each Random algorithm or serialization format
should have distinct prefix , 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,13,0)letget_int32_lesoff=letres=ref Int32.zeroinfori=3downto0doletv=Int32.of_int(Char.codes.[off+i])inres:=Int32.(addv(shift_left!res8))done;!resletget_int8soff=Char.codes.[off]letstarts_with ~prefixs=letopenStringinletlen_s=lengthsandlen_pre=lengthprefixinlet recauxi=ifi=len_prethentrueelseifunsafe_getsi<>unsafe_get prefixithenfalseelseaux(i+1)inlen_s>=len_pre&&aux0#elseletget_int32_le =String.get_int32_leletget_int8=String.get_int8letstarts_with =String.starts_with#endifletto_binary_strings=letprefix=serialization_prefixinletpreflen =serialization_prefix_leninletbuf=Bytes.create(preflen+55*4+1)inBytes.blit_stringprefix0buf0preflen;fori=0to54doBytes.set_int32_lebuf(preflen+i*4)(Int32.of_int(s.st.(i)land0x3FFFFFFF))done;Bytes.set_int8buf(preflen+55*4)s.idx;Bytes.unsafe_to_string bufletof_binary_stringbuf=letprefix=serialization_prefix inletpreflen=serialization_prefix_leninifString.length buf<>preflen+1+55*4||not(starts_with~prefixbuf)thenfailwith("Random3.State.of_binary_string: expected a format \
compatible with Random3 PRNG");letst=new_state()infori=0to54doletn=get_int32_le buf(preflen+i*4)inst.st.(i)<-Int32.(to_int@@logandn0x3FFFFFFFl)done;st.idx<-get_int8buf(preflen+55*4);stletfull_initsseed =letcombineaccux=Digest.string(accu^Int.to_string x)inletextractd=(Char.coded.[0]+(Char.coded.[1]lsl8)+(Char.coded.[2]lsl16))lxor (Char.coded.[3]lsl22)inletseed=ifArray.lengthseed=0then[|0|]elseseed inletl=Array.lengthseedinfori=0to54dos.st.(i)<-i;done;letaccu=ref"x"infori=0to54+max55ldolet j=imod55inletk=imodlinaccu:=combine!accu seed.(k);s.st.(j)<-s.st.(j)lxor extract!accu;done;s.idx<-0letmakeseed=letresult=new_state()infull_initresultseed;resultletmake_self_init()=make(random_seed())letcopys=letresult=new_state()inassignresults;result(* Returns30 random bits as an integer 0 <= x <1073741824 *)letbitss=s.idx<-(s.idx+1)mod55;letnewval=(s.st.((s.idx+24)mod55)+s.st.(s.idx))land 0x3FFFFFFFins.st.(s.idx)<-newval;newvalletrecintauxsn=letr=bitssinletv=rmodninifr-v>0x3FFFFFFF -n+1thenintauxsnelsevlet intsbound=ifbound>0x3FFFFFFF||bound<= 0theninvalid_arg"Random.int"elseintauxsboundletrecint63auxsn=letmax_int_32=(1lsl30)+0x3FFFFFFFin(* 0x7FFFFFFF *)letb1=bitssinletb2=bits sinlet(r,max_int)=ifn<=max_int_32then(* 31 random bits on both 64-bit OCaml and JavaScript.
Use upper 15 bitsof b1and 16 bitsofb2.*)letbpos=(((b2land0x3FFFC000)lsl1)lor (b1lsr15))in(bpos,max_int_32)elseletb3=bitssin(* 62 randombits on 64-bit OCaml; unreachable on JavaScript.
Use upper 20 bits of b1 and 21 bits of b2 and b3. *)letbpos=((((b3land0x3FFFFE00)lsl12)lor(b2lsr9))lsl20)lor(b1lsr10)in(bpos,max_int)inletv=rmodninifr-v>max_int-n+1thenint63auxsnelsevletfull_intsbound=ifbound<=0theninvalid_arg"Random.full_int"elseifbound>0x3FFFFFFFthenint63auxsboundelseintauxsboundletrecint32auxsn=letb1=Int32.of_int(bitss)inletb2=Int32.shift_left(Int32.of_int(bitssland1))30 inletr=Int32.logorb1b2inletv=Int32.remrninifInt32.subrv>Int32.add(Int32.subInt32.max_intn)1lthenint32auxsnelsevletint32sbound=ifbound<=0ltheninvalid_arg"Random.int32"elseint32auxsboundletrecint64auxsn=letb1=Int64.of_int(bitss)inletb2=Int64.shift_left(Int64.of_int(bitss))30inletb3=Int64.shift_left(Int64.of_int(bitssland7))60inletr=Int64.logorb1(Int64.logorb2b3)inletv=Int64.remrninifInt64.subrv>Int64.add(Int64.subInt64.max_int n)1Lthenint64auxsnelsevlet int64sbound=ifbound<=0Ltheninvalid_arg"Random.int64"elseint64auxsboundletnativeint =ifNativeint.size=32thenfunsbound->Nativeint.of_int32(int32s(Nativeint.to_int32bound))elsefunsbound->Int64.to_nativeint(int64s(Int64.of_nativeint bound))(* Returns a float 0 <= x < 1 with at most 90 bits of precision. *)letrawfloat s=letscale=1073741824.0andr0=float_of_int(bitss)andr1=float_of_int(bitss)andr2=float_of_int (bitss)in((r0 /.scale+.r1)/.scale+.r2)/.scalelet floatsbound=rawfloat s*.boundletbools=(bitssland1=0)letbits32s=letb1=Int32.(shift_right_logical(of_int(bitss))14)in(* 16 bits *)letb2=Int32.(shift_right_logical(of_int(bitss))14)in(* 16 bits *)Int32.(logorb1(shift_left b216))letbits64s=letb1=Int64.(shift_right_logical(of_int(bitss))9)in(* 21 bits *)letb2=Int64.(shift_right_logical(of_int(bitss))9)in(* 21 bits *)letb3=Int64.(shift_right_logical(of_int(bitss))8)in(* 22 bits *)Int64.(logorb1(logor(shift_leftb221)(shift_leftb342)))letnativebits=ifNativeint.size=32thenfuns->Nativeint.of_int32(bits32s)elsefuns->Int64.to_nativeint(bits64s)end(* This is the state you get with [init 27182818] on a 32-bit machine. *)letdefault={State.st=[|509760043;399328820;99941072;112282318;611886020;516451399;626288598;337482183;748548471;808894867;657927153;386437385;42355480;977713532;311548488;13857891;307938721;93724463;1041159001;444711218;1040610926;233671814;664494626;1071756703;188709089;420289414;969883075;513442196;275039308;918830973;598627151;134083417;823987070;619204222;81893604;871834315;398384680;475117924;520153386;324637501;38588599;435158812;168033706;585877294;328347186;293179100;671391820;846150845;283985689;502873302;718642511;938465128;962756406;107944131;192910970;|];State.idx=0;}letbits()=State.bits defaultletintbound=State.intdefaultboundletfull_intbound=State.full_intdefaultboundletint32bound=State.int32defaultboundletnativeintbound=State.nativeintdefaultboundletint64bound=State.int64defaultboundletfloatscale=State.floatdefaultscaleletbool()=State.booldefaultletbits32()=State.bits32defaultletbits64()=State.bits64defaultletnativebits()=State.nativebitsdefaultletfull_initseed=State.full_initdefaultseedletinitseed=State.full_initdefault[|seed|]letself_init()=full_init(random_seed())(* Manipulating the current state. *)letget_state()=State.copydefaultletset_states=State.assigndefaults(********************
(* Test functions. Not included in the library.
The [chisquare] function should be called with n > 10r.
It returns a triple (low, actual, high).
If low <= actual <= high, the [g] function passed the test,
otherwise it failed.
Some results:
init 27182818; chisquare int 100000 1000
init 27182818; chisquare int 100000 100
init 27182818; chisquare int 100000 5000
init 27182818; chisquare int 1000000 1000
init 27182818; chisquare int 100000 1024
init 299792643; chisquare int 100000 1024
init 14142136; chisquare int 100000 1024
init 27182818; init_diff 1024; chisquare diff 100000 1024
init 27182818; init_diff 100; chisquare diff 100000 100
init 27182818; init_diff2 1024; chisquare diff2 100000 1024
init 27182818; init_diff2 100; chisquare diff2 100000 100
init 14142136; init_diff2 100; chisquare diff2 100000 100
init 299792643; init_diff2 100; chisquare diff2 100000 100
- : float * float * float = (936.754446796632465, 1032., 1063.24555320336754)
# - : float * float * float = (80., 91.3699999999953434, 120.)
# - : float * float * float = (4858.57864376269026, 4982., 5141.42135623730974)
# - : float * float * float =
(936.754446796632465, 1017.99399999994785, 1063.24555320336754)
# - : float * float * float = (960., 984.565759999997681, 1088.)
# - : float * float * float = (960., 1003.40735999999742, 1088.)
# - : float * float * float = (960., 1035.23328000000038, 1088.)
# - : float * float * float = (960., 1026.79551999999967, 1088.)
# - : float * float * float = (80., 110.194000000003143, 120.)
# - : float * float * float = (960., 1067.98080000000482, 1088.)
# - : float * float * float = (80., 107.292000000001281, 120.)
# - : float * float * float = (80., 85.1180000000022119, 120.)
# - : float * float * float = (80., 86.614000000001397, 120.)
*)
(* Return the sum of the squares of v[i0,i1[ *)
let rec sumsq v i0 i1 =
if i0 >= i1 then 0.0
else if i1 = i0 + 1 then Stdlib.float v.(i0) *. Stdlib.float v.(i0)
else sumsq v i0 ((i0+i1)/2) +. sumsq v ((i0+i1)/2) i1
let chisquare g n r =
if n <= 10 * r then invalid_arg "chisquare";
let f = Array.make r 0 in
for i = 1 to n do
let t = g r in
f.(t) <- f.(t) + 1
done;
let t = sumsq f 0 r
and r = Stdlib.float r
and n = Stdlib.float n in
let sr = 2.0 *. sqrt r in
(r -. sr, (r *. t /. n) -. n, r +. sr)
(* This is to test for linear dependencies between successive random numbers.
*)
let st = ref 0
let init_diff r = st := int r
let diff r =
let x1 = !st
and x2 = int r
in
st := x2;
if x1 >= x2 then
x1 - x2
else
r + x1 - x2
let st1 = ref 0
and st2 = ref 0
(* This is to test for quadratic dependencies between successive random
numbers.
*)
let init_diff2 r = st1 := int r; st2 := int r
let diff2 r =
let x1 = !st1
and x2 = !st2
and x3 = int r
in
st1 := x2;
st2 := x3;
(x3 - x2 - x2 + x1 + 2*r) mod r
********************)