123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528(***********************************************************************)(* *)(* 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+max55ldoletj=imod55inletk=imodlinaccu:=combine!accuseed.(k);s.st.(j)<-s.st.(j)lxorextract!accu;done;s.idx<-0letmakeseed=letresult=new_state()infull_initresultseed;resultletmake_self_init()=make (random_seed())letcopys=letresult=new_state()inassignresults;resultletmin_int31=-0x4000_0000(* =-2{^30},which is [min_int] for 31-bit integers *)letmax_int31=0x3FFF_FFFF(* = 2{^30}-1, which is [max_int]for 31-bit integers *)(* avoid integer literals for these, 32-bit OCaml would reject them: *)letmin_int32=-(1lsl31)(* = -0x8000_0000 on platforms where [Sys.int_size >= 32] *)letmax_int32=(1lsl31)-1(* = 0x7FFF_FFFF on platforms where [Sys.int_size >= 32] *)(* Return 30 random bits as an integer 0 <= x < 2^30 *)letbitss=s.idx<-(s.idx+1)mod 55;letnewval=(s.st.((s.idx+24)mod55)+s.st.(s.idx))land0x3FFFFFFFins.st.(s.idx)<-newval;newvalletbits32s=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_leftb216))letbits64s=letb1=Int64.(shift_right_logical(of_int(bitss))9)in(* 21bits*)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)))(* Return 32 or 64 random bits as a [nativeint]*)letnativebits=ifNativeint.size=32thenfuns->Nativeint.of_int32(bits32s)elsefuns->Int64.to_nativeint(bits64s)letrecint31auxsn=letr=bitssinletv=rmodninifr-v>max_int31-n+1thenint31auxsnelsevletintsbound=ifbound>max_int31||bound<=0theninvalid_arg"Random.int"elseint31auxsboundletrecint63auxsn=letb1=bitssinletb2=bitssinlet(r,max_int)=ifn<=max_int32then(* 31 random bitson both 64-bit OCaml and JavaScript. Use upper 15bitsof b1 and 16 bitsofb2. *)letbpos=(((b2land0x3FFFC000)lsl1)lor (b1lsr15))in(bpos,max_int32)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>0x3FFFFFFFthenint63auxsboundelseint31auxsbound(* Return an integer between 0 (included)and [n] (excluded).
[bound] may be any positive [int]. [mask] must be of the form [2{^i}-1]
and greater or equal to [n]. Larger values of [mask] make the function
run faster (fewer samples are rejected). Smaller values of [mask]
are usable on a wider range of OCaml implementations. *)letrecint_auxsnmask=(* We start by drawing a non-negative integer in the [ [0, mask] ] range *)letr=Int64.to_int(bits64s)landmaskinletv=rmodnin(* For uniform distribution of the result between 0 includedand [n] * excluded, therandom number[r] must have been drawn uniformly in
* an interval whose length is a multiple of [n]. To achieve this,
* we use rejection sampling on the greatest interval [ [0, k*n-1] ]
* that fits in [ [0, mask] ]. That is, we reject the
* sample if it falls outside of this interval, and draw again.
* This is what the test below does, while carefully avoiding
* overflows and sparing a division [mask / n]. *)ifr-v>mask-n+1thenint_auxsnmaskelsev(* Return an integer between [min] (included) and [max] (included).
The [nbits] parameter isthe size in bits of the signed integers
we draw from [s].
We must have [-2{^nbits - 1} <= min <= max < 2{^nbits - 1}].
Moreover, for the iterationto converge quickly, the interval
[[min, max]] should havewidth at least [2{^nbits - 1}].
As the width approaches this lower limit, the average number of
draws approaches 2, with a quite high standard deviation (2 + epsilon). *)letrecint_in_large_ranges~min~max~nbits=letdrop=Sys.int_size-nbitsin(* The bitshifts replicate the [nbits]-thbit (sign bit) to higher bits: *)letr=((Int64.to_int(bits64s))lsldrop)asrdropinifr<min||r>maxthenint_in_large_ranges~min~max~nbits else r(* Return an integer between [min] (included) and [max] (included).
[mask] is as described for [int_aux].
[nbits] is as described for [int_in_large_range]. *)letint_in_range_auxs~min~max~mask~nbits=letspan=max-min+1inifspan<=mask(*[span] is small enough *)&&span>0(*no overflow occurred when computing [span] *)then(* Just draw a number in [[0, span)] and shift it by [min]. *)min+int_auxsspanmaskelse(* Span too large, use the alternative drawing method. *)int_in_large_ranges~min~max~nbits(* 31bits version to account for the 31 bit PRNG *)letrecint31_in_large_ranges~min~max=letr=Int32.to_int(bits32s)inifr<min||r>maxthenint31_in_large_ranges~min~maxelserletint31_in_range_auxs~min~max=letmask=max_int31inletspan=max-min+1inif span<=mask(* [span] is small enough *)&&span>0(* no overflow occurred when computing [span] *)then(* Just draw a number in [[0, span)] and shift it by [min]. *)min+int31auxsspanelse(* Span too large, use the alternative drawing method. *)int31_in_large_ranges~min~max(* Return an integer between [min] (included) and [max] (included).
We must have [min <= max]. *)letint_in_ranges~min~max=if min>maxtheninvalid_arg"Random.int_in_range";(* When both bounds fit in31-bit signed integers, we use parameters
[mask] and [nbits] appropriate for 31-bit integers, so as to
yield the sameoutput on all platforms supported by OCaml.
When both boundsfit in 32-bit signed integers, we use parameters
[mask] and [nbits] appropriate for 32-bit integers, so as to yield the same output on JavaScript andon 64-bit OCaml. *)ifmin>=min_int31&&max<=max_int31thenint31_in_range_auxs~min~maxelseifmin>= min_int32&&max<=max_int32thenint_in_range_auxs~min~max~mask:max_int32~nbits:32elseint_in_range_auxs~min~max~mask:max_int~nbits:Sys.int_sizeletrecint32auxsn=letb1=Int32.of_int(bits s)inletb2=Int32.shift_left(Int32.of_int(bitssland1))30inlet r=Int32.logorb1b2inletv=Int32.rem rninifInt32.subrv>Int32.add(Int32.subInt32.max_intn)1lthenint32auxsnelse vletint32sbound=ifbound<=0ltheninvalid_arg"Random.int32"elseint32auxsbound(*Return an [int32] between [min] (included) and [max] (included).
We must have [min <= max]. *)let recint32_in_range_auxs~min~max=letr=bits32 sinifr<min||r>maxthenint32_in_range_auxs~min~maxelserlet int32_in_ranges~min~max=ifmin>max theninvalid_arg"Random.int32_in_range"elseletspan=Int32.succ(Int32.submaxmin)in(* Explanation ofthis test: seecomment in [int_in_range_aux]. *)ifspan<=Int32.zerothenint32_in_range_aux s~min~maxelseInt32.addmin(int32auxsspan)letrecint64auxsn=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.rem rninifInt64.subrv>Int64.add(Int64.subInt64.max_intn)1Lthenint64auxsnelse vletint64sbound=ifbound<=0Ltheninvalid_arg"Random.int64"elseint64auxsbound(*Return an [int64] between [min] (included) and [max] (included).
We must have [min <= max]. *)let recint64_in_range_auxs~min~max=letr=bits64sinifr<min||r>maxthen int64_in_range_auxs~min~maxelserletint64_in_ranges~min~max=ifmin>maxtheninvalid_arg "Random.int64_in_range"elseletspan=Int64.succ(Int64.submaxmin)in(* Explanation of this test: see comment in [int_in_range_aux]. *)ifspan<=Int64.zerothenint64_in_range_aux s~min~maxelseInt64.addmin(int64auxsspan)(* 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 [nativeint] between [min] (included) and [max] (included). *)letnativeint_in_range=ifNativeint.size=32thenfuns~min~max->Nativeint.of_int32(int32_in_ranges~min:(Nativeint.to_int32min)~max:(Nativeint.to_int32max))elsefuns~min~max->Int64.to_nativeint(int64_in_ranges~min:(Int64.of_nativeintmin)~max:(Int64.of_nativeintmax))(* Returns a float 0 <= x < 1 with at most 90 bits of precision. *)letrawfloats=letscale=1073741824.0andr0=float_of_int(bitss)andr1=float_of_int(bitss)andr2=float_of_int(bitss)in((r0/.scale+.r1)/.scale+.r2)/.scaleletfloatsbound=rawfloats*.boundletbools=(bitssland1=0)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.bitsdefaultletintbound=State.intdefaultboundletfull_intbound=State.full_int defaultboundletint_in_range~min~max=State.int_in_rangedefault~min~maxletint32bound=State.int32defaultboundletint32_in_range~min~max=State.int32_in_range default~min~maxletnativeintbound=State.nativeintdefaultboundletnativeint_in_range~min~max=State.nativeint_in_rangedefault~min~maxletint64bound=State.int64defaultboundletint64_in_range~min~max=State.int64_in_rangedefault~min~maxletfloatscale=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
********************)