123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664openCore_kernelmoduleZ=Zarith.Z;;typet=Z.t[@@derivingtyperep~abstract];;moduleStable=structmoduleV1=structmoduleT0=structtypenonrect=t;;letmodule_name="Bigint";;letto_string=Z.to_string;;letrecis_integer_suffixsi~len~char_is_digit=ifi<lenthenletc=String.getsiinifchar_is_digitc||Char.equalc'_'thenis_integer_suffixs(i+1)~len~char_is_digitelsefalseelsetrue;;letis_integer_strings~char_is_digit=letlen=String.lengthsinif0<lenthenleti=ifChar.equal(String.gets0)'-'then1else0inifi<lenthenifchar_is_digit(String.getsi)thenis_integer_suffixs(i+1)~len~char_is_digitelsefalseelsefalseelsefalse;;letof_string_basestr~name~of_string_no_underscores~char_is_digit=tryof_string_no_underscoresstrwith_->ifis_integer_stringstr~char_is_digitthenof_string_no_underscores(String.filterstr~f:(func->c<>'_'))elsefailwithf"%s.%s: invalid argument %S"namemodule_namestr();;letof_stringstr=of_string_basestr~name:"of_string"~of_string_no_underscores:Z.of_string~char_is_digit:Char.is_digit;;letcompare=Z.compare;;moduleBinable=structtypet=Zero|Posofstring|Negofstring[@@derivingbin_io]end;;letto_binablet=lets=Z.signtinifs>0thenBinable.Pos(Z.to_bitst)elseifs<0thenBinable.Neg(Z.to_bitst)elseBinable.Zero;;letof_binable=function|Binable.Zero->Z.zero|Binable.Posbits->Z.of_bitsbits|Binable.Negbits->Z.of_bitsbits|>Z.neg;;endincludeSexpable.Stable.Of_stringable.V1(T0)includeBinable.Stable.Of_binable.V1(T0.Binable)(T0)includeT0;;endmoduleCurrent=V1;;end;;moduleT=structincludeStable.Current;;letof_zarith_bigintt=tletto_zarith_bigintt=t;;let(/%)xy=ifZ.signy>=0thenZ.edivxyelsefailwithf"%s.(%s /%% %s) : divisor must be positive"module_name(to_stringx)(to_stringy)();;let(%)xy=ifZ.signy>=0thenZ.eremxyelsefailwithf"%s.(%s %% %s) : divisor must be positive"module_name(to_stringx)(to_stringy)();;lethash_fold_t=funstatet->Int.hash_fold_tstate(Z.hasht)lethash=Z.hashletcompare=Z.compare;;let(-)=Z.(-)let(+)=Z.(+)let(*)=Z.(*)let(/)=Z.(/);;letrem=Z.rem;;let(~-)=Z.(~-)letneg=Z.negletabs=Z.absletsucc=Z.succletpred=Z.pred;;letequal=Z.equallet(=)=Z.equallet(<)=Z.ltlet(>)=Z.gtlet(<=)=Z.leqlet(>=)=Z.geqletmax=Z.maxletmin=Z.minletascending=compare;;letshift_right=Z.shift_rightletshift_left=Z.shift_leftletbit_not=Z.lognotletbit_xor=Z.logxorletbit_or=Z.logorletbit_and=Z.logand;;let(land)=bit_andlet(lor)=bit_orlet(lxor)=bit_xorlet(lnot)=bit_notlet(lsl)=shift_leftlet(asr)=shift_right;;letof_int=Z.of_intletof_int32=Z.of_int32letof_int64=Z.of_int64letof_nativeint=Z.of_nativeintletof_float_unchecked=Z.of_floatletof_float=Z.of_float;;letof_int_exn=of_intletof_int32_exn=of_int32letof_int64_exn=of_int64letof_nativeint_exn=of_nativeint;;letto_int_exn=Z.to_intletto_int32_exn=Z.to_int32letto_int64_exn=Z.to_int64letto_nativeint_exn=Z.to_nativeintletto_float=Z.to_float;;letzero=Z.zeroletone=Z.oneletminus_one=Z.minus_one;;letto_intt=ifZ.fits_inttthenSome(Z.to_intt)elseNoneletto_int32t=ifZ.fits_int32tthenSome(Z.to_int32t)elseNoneletto_int64t=ifZ.fits_int64tthenSome(Z.to_int64t)elseNoneletto_nativeintt=ifZ.fits_nativeinttthenSome(Z.to_nativeintt)elseNone;;let(<>)xy=not(equalxy);;letincrcell=cell:=succ!cellletdecrcell=cell:=pred!cell;;letpowxy=Z.powx(to_int_exny);;let(**)xy=powxyletpopcountx=Z.popcountx;;end;;moduleT_math=Base.Not_exposed_properly.Int_math.Make(T)moduleT_conversions=Base.Not_exposed_properly.Int_conversions.Make(T)moduleT_comparable_with_zero=Comparable.Validate_with_zero(T)moduleT_identifiable=Identifiable.Make(T);;(* Including in opposite order to shadow functorized bindings with direct bindings. *)moduleO=structincludeT_identifiableincludeT_comparable_with_zeroincludeT_conversionsincludeT_mathincludeTend;;include(O:moduletypeofOwithtypet:=t);;moduleMake_random(State:sigtypetvalbits:t->intvalint:t->int->intend):sigvalrandom:state:State.t->t->tend=struct(* Uniform random generation of Bigint values.
[random ~state range] chooses a [depth] and generates random values using
[Random.State.bits state], called [1 lsl depth] times and concatenated. The
preliminary result [n] therefore satisfies [0 <= n < 1 lsl (30 lsl depth)].
In order for the random choice to be uniform between [0] and [range-1], there must
exist [k > 0] such that [n < k * range <= 1 lsl (30 lsl depth)]. If so, [n % range]
is returned. Otherwise the random choice process is repeated from scratch.
The [depth] value is chosen so that repeating is uncommon (1 in 1,000 or less). *)letbits_at_depth~depth=Int.shift_left30depthletrange_at_depth~depth=shift_leftone(bits_at_depth~depth)letrecchoose_bit_depth_for_range_from~range~depth=ifrange_at_depth~depth>=rangethendepthelsechoose_bit_depth_for_range_from~range~depth:(Int.succdepth);;letchoose_bit_depth_for_range~range=choose_bit_depth_for_range_from~range~depth:0;;letrecrandom_bigint_at_depth~state~depth=ifInt.equaldepth0thenof_int(State.bitsstate)elseletprev_depth=Int.preddepthinletprefix=random_bigint_at_depth~state~depth:prev_depthinletsuffix=random_bigint_at_depth~state~depth:prev_depthinbit_or(shift_leftprefix(bits_at_depth~depth:prev_depth))suffix;;letrandom_value_is_uniform_in_range~range~depthn=letk=range_at_depth~depth/rangeinn<k*range;;letreclarge_random_at_depth~state~range~depth=letresult=random_bigint_at_depth~state~depthinifrandom_value_is_uniform_in_range~range~depthresultthenresult%rangeelselarge_random_at_depth~state~range~depth;;letlarge_random~state~range=lettolerance_factor=of_int1_000inletdepth=choose_bit_depth_for_range~range:(range*tolerance_factor)inlarge_random_at_depth~state~range~depth;;letrandom~staterange=ifrange<=zerothenfailwithf"Bigint.random: argument %s <= 0"(to_string_humrange)()(* Note that it's not safe to do [1 lsl 30] on a 32-bit machine (with 31-bit signed
integers) *)elseifrange<shift_leftone30thenof_int(State.intstate(to_int_exnrange))elselarge_random~state~range;;endmoduleRandom_internal=Make_random(Random.State)letrandom?(state=Random.State.default)range=Random_internal.random~staterangelet%test_unit"random"=letstate=Random.State.make[|1;2;3|]inletrange=shift_leftone100inletseen=Hash_set.create()infor_=1to100_000dolett=random~staterangeinift<zero||t>=rangethenfailwith"random result out of bounds";Core_kernel.Hash_set.strict_add_exnseentdone;;moduleFor_quickcheck:sigincludeQuickcheckable.S_intwithtypet:=tvalgen_negative:tQuickcheck.Generator.tvalgen_positive:tQuickcheck.Generator.tend=structmoduleGenerator=Quickcheck.GeneratoropenGenerator.Let_syntaxmoduleUniform=Make_random(structtypet=Splittable_random.State.tletinttrange=Splittable_random.intt~lo:0~hi:(Int.predrange)letbitst=intt(Int.shift_left130)end)letrandom_uniform~statelohi=lo+Uniform.random~state(succ(hi-lo))letgen_uniform_incllower_boundupper_bound=iflower_bound>upper_boundthenbeginraise_s[%message"Bigint.gen_uniform_incl: bounds are crossed"(lower_bound:t)(upper_bound:t)]end;Generator.create(fun~size:_~random:state->random_uniform~statelower_boundupper_bound)letgen_incllower_boundupper_bound=Generator.weighted_union[0.05,Generator.returnlower_bound;0.05,Generator.returnupper_bound;0.9,gen_uniform_incllower_boundupper_bound]letmin_represented_by_n_bitsn=ifInt.equaln0thenzeroelseshift_leftone(Int.predn)letmax_represented_by_n_bitsn=pred(shift_leftonen)letgen_log_uniform_incllower_boundupper_bound=iflower_bound<zero||lower_bound>upper_boundthenbeginraise_s[%message"Bigint.gen_log_incl: invalid bounds"(lower_bound:t)(upper_bound:t)]end;letmin_bits=Z.numbitslower_boundinletmax_bits=Z.numbitsupper_boundinlet%bindbits=Int.gen_uniform_inclmin_bitsmax_bitsingen_uniform_incl(maxlower_bound(min_represented_by_n_bitsbits))(minupper_bound(max_represented_by_n_bitsbits))letgen_log_incllower_boundupper_bound=Generator.weighted_union[0.05,Generator.returnlower_bound;0.05,Generator.returnupper_bound;0.9,gen_log_uniform_incllower_boundupper_bound]letgen_positive=let%bindextra_bytes=Generator.sizeinletnum_bytes=Int.succextra_bytesinletnum_bits=Int.(*)num_bytes8ingen_log_uniform_inclone(pred(shift_leftonenum_bits))letgen_negative=Generator.mapgen_positive~f:negletquickcheck_generator=Generator.weighted_union[0.45,gen_positive;0.1,Generator.returnzero;0.45,gen_negative]letquickcheck_observer=Quickcheck.Observer.create(funt~size:_~hash->hash_fold_thasht)letquickcheck_shrinker=Quickcheck.Shrinker.empty()endincludeFor_quickcheckmoduleHex=structtypenonrect=t[@@derivingbin_io,typerep]moduleM=Base.Not_exposed_properly.Int_conversions.Make_hex(structtypenonrect=t[@@derivinghash,compare];;letto_stringi=Z.format"%x"i;;letchar_is_hex_digit=function|'0'..'9'|'a'..'f'|'A'..'F'->true|_->false;;letof_hex_string_no_underscoresstr=Z.of_string_base16str;;letof_stringstr=of_string_basestr~name:"Hex.of_string"~char_is_digit:char_is_hex_digit~of_string_no_underscores:of_hex_string_no_underscores;;let(<)=(<)letneg=negletzero=zeroletmodule_name=module_name^".Hex"end)include(M.Hex:moduletypeofstructincludeM.Hexendwithtypet:=t)end;;let%test_module"stable bin_io"=(modulestructletarray=Array.init10~f:(funi->pow(of_int1_000_000_000)(of_inti));;letsize_of_buf=1024letbuf=Bigstring.createsize_of_buflet%test_unit"round-trip"=forpos=0to20doArray.iterarray~f:(funt->letsize_of_t=Stable.V1.bin_size_ttinassertInt.(size_of_t+pos<=size_of_buf);letnew_pos=Stable.V1.bin_writer_t.Bin_prot.Type_class.writebuf~postinletpos_ref=refposinlett1=Stable.V1.bin_reader_t.Bin_prot.Type_class.readbuf~pos_refin[%test_result:Stable.V1.t]t1~expect:t;[%test_result:int]!pos_ref~expect:new_pos;)done;;end)let%test_module"vs Int"=(modulestructlet%test_unit"constants"=[%test_eq:int]Int.zero(to_int_exnzero);[%test_eq:int]Int.one(to_int_exnone);[%test_eq:int]Int.minus_one(to_int_exnminus_one);;let%test_unit"unary"=letnums=[-1001001001;-1001001;-1001;-1;0;1;1234;1234567;123456789]inletops=[Int.(~-),(~-),"( ~- )";Int.neg,neg,"neg";Int.abs,abs,"abs";Int.succ,succ,"succ";Int.pred,pred,"pred";Int.bit_not,bit_not,"bit_not"]inList.iterops~f:(fun(int_op,big_op,op_str)->List.iternums~f:(funint_x->letexpect=Option.try_with(fun()->int_opint_x)inletbig_x=of_int_exnint_xinletbig_actual=Option.try_with(fun()->big_opbig_x)inletint_actual=Option.mapbig_actual~f:to_int_exnin[%test_result:intoption]~message:(sprintf"Bigint does not match [Int.%s %d]"op_strint_x)~expectint_actual));;let%test_unit"binops"=letnums=[-10101;-101;-1;0;1;123;12345]inletwrap_roundfxy=fx~to_multiple_of:yinletwrap_comparefxy=of_int_exn(fxy)inletops=[Int.(+),(+),"( + )";Int.(-),(-),"( - )";Int.(*),(*),"( * )";Int.(/),(/),"( / )";Int.rem,rem,"rem";Int.(/%),(/%),"( /% )";Int.(%),(%),"( % )";Int.bit_and,bit_and,"bit_and";Int.bit_or,bit_or,"bit_or";Int.bit_xor,bit_xor,"bit_xor";Int.compare,wrap_comparecompare,"compare";wrap_roundInt.round_down,wrap_roundround_down,"round_down";wrap_roundInt.round_up,wrap_roundround_up,"round_up";wrap_roundInt.round_nearest,wrap_roundround_nearest,"round_nearest";(wrap_roundInt.round_towards_zero,wrap_roundround_towards_zero,"round_towards_zero")]inList.iterops~f:(fun(int_op,big_op,op_str)->List.iternums~f:(funint_x->List.iternums~f:(funint_y->letexpect=Option.try_with(fun()->int_opint_xint_y)inletbig_x=of_int_exnint_xinletbig_y=of_int_exnint_yinletbig_actual=Option.try_with(fun()->big_opbig_xbig_y)inletint_actual=Option.mapbig_actual~f:to_int_exnin[%test_result:intoption]~message:(sprintf"Bigint does not match [Int.%s %d %d]"op_strint_xint_y)~expectint_actual)));;let%test_unit"comparisons"=letnums=[-1001001001;-1001001;-1001;-1;0;1;1234;1234567;123456789]inletops=[Int.(<>),(<>),"( <> )";Int.(<=),(<=),"( <= )";Int.(>=),(>=),"( >= )";Int.(<),(<),"( < )";Int.(>),(>),"( > )";Int.(=),(=),"( = )";Int.equal,equal,"equal"]inList.iterops~f:(fun(int_op,big_op,op_str)->List.iternums~f:(funint_x->List.iternums~f:(funint_y->letexpect=int_opint_xint_yinletbig_x=of_int_exnint_xinletbig_y=of_int_exnint_yinletactual=big_opbig_xbig_yin[%test_result:bool]~message:(sprintf"Bigint does not match [Int.%s %d %d]"op_strint_xint_y)~expectactual)));;let%test_unit"shift"=letnums=[-10101;-101;-1;0;1;123;12345]inletops=[Int.shift_left,shift_left,"shift_left";Int.shift_right,shift_right,"shift_right"]inList.iterops~f:(fun(int_op,big_op,op_str)->List.iternums~f:(funint_x->forint_y=0to15doletexpect=Option.try_with(fun()->int_opint_xint_y)inletbig_x=of_int_exnint_xinletbig_actual=Option.try_with(fun()->big_opbig_xint_y)inletint_actual=Option.mapbig_actual~f:to_int_exnin[%test_result:intoption]~message:(sprintf"Bigint does not match [Int.%s %d %d]"op_strint_xint_y)~expectint_actualdone));;let%test_unit"pow"=letbases=[-101;-11;-1;0;1;12;123]inList.iterbases~f:(funbase->forexpt=-4to4doletexpect=Option.try_with(fun()->Int.powbaseexpt)inletbig_base=of_int_exnbaseinletbig_expt=of_int_exnexptinletbig_actual=Option.try_with(fun()->powbig_basebig_expt)inletint_actual=Option.mapbig_actual~f:to_int_exnin[%test_result:intoption]~message:(sprintf"Bigint does not match [Int.pow %d %d]"baseexpt)~expectint_actualdone);;let%test_unit"huge"=lethuge_val=pow(of_int_exn1001)(of_int_exn10)inlethuge_str="1010045120210252210120045010001"inlethuge_hum="1_010_045_120_210_252_210_120_045_010_001"inlethuge_hex="0xcbfa1bdc2045351f4de129c51"inlethuge_hex_hum="0xc_bfa1_bdc2_0453_51f4_de12_9c51"inlethuge_hex_caps=String.uppercasehuge_hex_huminlethuge_sexp=Sexp.Atomhuge_strinlethuge_hex_sexp=Sexp.Atomhuge_hexin[%test_result:intoption](Option.try_with(fun()->to_int_exnhuge_val))~expect:None;[%test_result:string](to_stringhuge_val)~expect:huge_str;[%test_result:string](to_string_humhuge_val)~expect:huge_hum;[%test_result:Sexp.t](sexp_of_thuge_val)~expect:huge_sexp;[%test_result:t](of_stringhuge_str)~expect:huge_val;[%test_result:t](of_stringhuge_hum)~expect:huge_val;[%test_result:t](t_of_sexphuge_sexp)~expect:huge_val;[%test_result:string](Hex.to_stringhuge_val)~expect:huge_hex;[%test_result:string](Hex.to_string_humhuge_val)~expect:huge_hex_hum;[%test_result:Sexp.t](Hex.sexp_of_thuge_val)~expect:huge_hex_sexp;[%test_result:t](Hex.of_stringhuge_hex)~expect:huge_val;[%test_result:t](Hex.of_stringhuge_hex_hum)~expect:huge_val;[%test_result:t](Hex.of_stringhuge_hex_caps)~expect:huge_val;[%test_result:t](Hex.t_of_sexphuge_hex_sexp)~expect:huge_val;;end);;