123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242open!ImportopenCaml.RandommoduleArray=Array0moduleInt=Int0(* Unfortunately, because the standard library does not expose
[Caml.Random.State.default], we have to construct our own. We then build the
[Caml.Random.int], [Caml.Random.bool] functions and friends using that default state in
exactly the same way as the standard library.
One other trickiness is that we need access to the unexposed [Caml.Random.State.assign]
function, which accesses the unexposed state representation. So, we copy the
[State.repr] type definition and [assign] function to here from the standard library,
and use [Obj.magic] to get access to the underlying implementation. *)(* Regression tests ought to be deterministic because that way anyone who breaks the test
knows that it's their code that broke the test. If tests are nondeterministic, a test
failure may instead happen because the test runner got unlucky and uncovered an
existing bug in the code supposedly being "protected" by the test in question. *)letforbid_nondeterminism_in_tests~allow_in_tests=ifam_testingthenmatchallow_in_testswith|Sometrue->()|None|Somefalse->failwith"\
initializing Random with a nondeterministic seed is forbidden in inline tests";;externalrandom_seed:unit->intarray="caml_sys_random_seed";;letrandom_seed?allow_in_tests()=forbid_nondeterminism_in_tests~allow_in_tests;random_seed();;moduleState=structincludeStateletmake_self_init?allow_in_tests()=forbid_nondeterminism_in_tests~allow_in_tests;make_self_init();;typerepr={st:intarray;mutableidx:int}letassignt1t2=lett1=(Caml.Obj.magict1:repr)inlett2=(Caml.Obj.magict2:repr)inArray.blit~src:t2.st~src_pos:0~dst:t1.st~dst_pos:0~len:(Array.lengtht1.st);t1.idx<-t2.idx;;;letfull_inittseed=assignt(makeseed)letdefault=(* We define Core's default random state as a copy of OCaml's default random state.
This means that programs that use Core.Random will see the same sequence of random
bits as if they had used Caml.Random. However, because [get_state] returns a
copy, Core.Random and OCaml.Random are not using the same state. If a program used
both, each of them would go through the same sequence of random bits. To avoid
that, we reset OCaml's random state to a different seed, giving it a different
sequence. *)lett=Caml.Random.get_state()inCaml.Random.init137;t;;letint_on_64bitstbound=ifbound<=0x3FFFFFFF(* (1 lsl 30) - 1 *)theninttboundelseCaml.Int64.to_int(int64t(Caml.Int64.of_intbound));;letint_on_32bitstbound=(* Not always true with the JavaScript backend. *)ifbound<=0x3FFFFFFF(* (1 lsl 30) - 1 *)theninttboundelseCaml.Int32.to_int(int32t(Caml.Int32.of_intbound));;letint=matchWord_size.word_sizewith|W64->int_on_64bits|W32->int_on_32bits;;letfull_range_int64=letopenCaml.Int64inletbitsstate=of_int(bitsstate)infunstate->logxor(bitsstate)(logxor(shift_left(bitsstate)30)(shift_left(bitsstate)60));;letfull_range_int32=letopenCaml.Int32inletbitsstate=of_int(bitsstate)infunstate->logxor(bitsstate)(shift_left(bitsstate)30);;letfull_range_int_on_64bitsstate=Caml.Int64.to_int(full_range_int64state);;letfull_range_int_on_32bitsstate=Caml.Int32.to_int(full_range_int32state);;letfull_range_int=matchWord_size.word_sizewith|W64->full_range_int_on_64bits|W32->full_range_int_on_32bits;;letfull_range_nativeint_on_64bitsstate=Caml.Int64.to_nativeint(full_range_int64state);;letfull_range_nativeint_on_32bitsstate=Caml.Nativeint.of_int32(full_range_int32state);;letfull_range_nativeint=matchWord_size.word_sizewith|W64->full_range_nativeint_on_64bits|W32->full_range_nativeint_on_32bits;;let[@inlinenever]raise_crossed_boundsnamelower_boundupper_boundstring_of_bound=Printf.failwithf"Random.%s: crossed bounds [%s > %s]"name(string_of_boundlower_bound)(string_of_boundupper_bound)();;letint_incl=letrecin_rangestatelohi=letint=full_range_intstateinifint>=lo&&int<=hithenintelsein_rangestatelohiinfunstatelohi->iflo>hithenraise_crossed_bounds"int"lohiInt.to_string;letdiff=hi-loinifdiff=Int.max_valuethenlo+((full_range_intstate)landInt.max_value)elseifdiff>=0thenlo+intstate(Int.succdiff)elsein_rangestatelohi;;letint32_incl=letopenInt32_replace_polymorphic_compareinletrecin_rangestatelohi=letint=full_range_int32stateinifint>=lo&&int<=hithenintelsein_rangestatelohiinletopenCaml.Int32infunstatelohi->iflo>hithenraise_crossed_bounds"int32"lohito_string;letdiff=subhiloinifdiff=max_intthenaddlo(logand(full_range_int32state)max_int)elseifdiff>=0lthenaddlo(int32state(succdiff))elsein_rangestatelohi;;letnativeint_incl=letopenNativeint_replace_polymorphic_compareinletrecin_rangestatelohi=letint=full_range_nativeintstateinifint>=lo&&int<=hithenintelsein_rangestatelohiinletopenCaml.Nativeintinfunstatelohi->iflo>hithenraise_crossed_bounds"nativeint"lohito_string;letdiff=subhiloinifdiff=max_intthenaddlo(logand(full_range_nativeintstate)max_int)elseifdiff>=0nthenaddlo(nativeintstate(succdiff))elsein_rangestatelohi;;letint64_incl=letopenInt64_replace_polymorphic_compareinletrecin_rangestatelohi=letint=full_range_int64stateinifint>=lo&&int<=hithenintelsein_rangestatelohiinletopenCaml.Int64infunstatelohi->iflo>hithenraise_crossed_bounds"int64"lohito_string;letdiff=subhiloinifdiff=max_intthenaddlo(logand(full_range_int64state)max_int)elseifdiff>=0Lthenaddlo(int64state(succdiff))elsein_rangestatelohi;;letfloat_rangestatelohi=letopenFloat_replace_polymorphic_compareiniflo>hithenraise_crossed_bounds"float"lohiCaml.string_of_float;lo+.floatstate(hi-.lo);;endletdefault=State.defaultletbits()=State.bitsdefaultletintx=State.intdefaultxletint32x=State.int32defaultxletnativeintx=State.nativeintdefaultxletint64x=State.int64defaultxletfloatx=State.floatdefaultxletint_inclxy=State.int_incldefaultxyletint32_inclxy=State.int32_incldefaultxyletnativeint_inclxy=State.nativeint_incldefaultxyletint64_inclxy=State.int64_incldefaultxyletfloat_rangexy=State.float_rangedefaultxyletbool()=State.booldefaultletfull_initseed=State.full_initdefaultseedletinitseed=full_init[|seed|]letself_init?allow_in_tests()=full_init(random_seed?allow_in_tests())letset_states=State.assigndefaults