123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153(* cilint: infinite-precision, 2's complement arithmetic. *)(* An infinite-precision 2's complement number is a good way of
understanding the meaning of bitwise operations on infinite
precision numbers: positive numbers have the normal base-2
representation, while negative numbers are represented in
a 2's complement representation with an infinite series of
leading 1 bits. I.e.,
3 = ...0000000000011
-3 = ...1111111111101
We represent cilints using a big_int but define some operations differently *)openBig_int_Ztypecilint=big_inttypetruncation=NoTruncation|ValueTruncation|BitTruncationletzero_cilint=zero_big_intletone_cilint=unit_big_intletmone_cilint=minus_big_intunit_big_int(* Precompute useful big_ints *)letb30=shift_left_big_intunit_big_int30letm1=minus_big_intunit_big_int(* True if 'b' is all 0's or all 1's *)letnobits(b:big_int):bool=sign_big_intb=0||compare_big_intbm1=0letbig_int_of_cilint(c:cilint):big_int=cletcilint_of_big_int(b:big_int):cilint=bletneg_cilint=minus_big_intletadd_cilint=add_big_intletsub_cilint=sub_big_intletmul_cilint=mult_big_intletdiv_cilint=div_big_intletmod_cilint=mod_big_intletcompare_cilint=compare_big_intletis_zero_cilint(c:cilint):bool=sign_big_intc=0letcilint_of_int=big_int_of_intletint_of_cilint=int_of_big_intletcilint_of_int64(i64:int64):cilint=big_int_of_int64i64(* Note that this never fails, instead it returns the low-order 64-bits
of the cilint. *)letint64_of_cilint(b:cilint):int64=letrecloopbmulacc=ifsign_big_intb=0thenaccelseifcompare_big_intbm1==0thenInt64.subaccmulelselethi,lo=quomod_big_intbb30inloophi(Int64.mulmul0x40000000L)(Int64.addacc(Int64.mulmul(Int64.of_int(int_of_big_intlo))))inloopb1L0Lletcilint_of_string=big_int_of_stringletstring_of_cilint=string_of_big_int(* Divide rounding towards zero *)letdiv0_cilint(c1:cilint)(c2:cilint)=letq,r=quomod_big_intc1c2iniflt_big_intc1zero_big_int&&(not(eq_big_intrzero_big_int))thenifgt_big_intc2zero_big_intthen(succ_big_intq)else(pred_big_intq)elseq(* And the corresponding remainder! Different from *)(* Big_int_Z.mod_big_int computes the Euclidian Modulus, but what we want here is the remainder, as returned by mod on ints
-1 rem 5 == -1, whereas -1 Euclid-Mod 5 == 4
*)letrem_cilint(c1:cilint)(c2:cilint)=(sub_cilintc1(mul_cilintc2(div0_cilintc1c2)))(* Perform logical op 'op' over 'int' on two cilints. Does it work
30-bits at a time as that is guaranteed to fit in an 'int'. *)letlogopopc1c2=letrecloopb1b2mulacc=ifnobitsb1&&nobitsb2then(* Once we only have all-0/all-1 values left, we can find whether
the infinite high-order bits are all-0 or all-1 by checking the
behaviour of op on b1 and b2. *)ifop(int_of_big_intb1)(int_of_big_intb2)=0thenaccelsesub_big_intaccmulelselethi1,lo1=quomod_big_intb1b30inlethi2,lo2=quomod_big_intb2b30inletlo=op(int_of_big_intlo1)(int_of_big_intlo2)inloophi1hi2(mult_big_intmulb30)(add_big_intacc(mult_big_intmul(big_int_of_intlo)))inloopc1c2unit_big_intzero_big_intletlogand_cilint=logop(land)letlogor_cilint=logop(lor)letlogxor_cilint=logop(lxor)letshift_right_cilint(c1:cilint)(n:int):cilint=shift_right_towards_zero_big_intc1nletshift_left_cilint(c1:cilint)(n:int):cilint=shift_left_big_intc1nletlognot_cilint(c1:cilint):cilint=(pred_big_int(minus_big_intc1))lettruncate_signed_cilint(c:cilint)(n:int):cilint*truncation=letmax=shift_left_big_intunit_big_int(n-1)inlettruncmax=shift_left_big_intunit_big_intninletbits=mod_big_intctruncmaxinlettval=iflt_big_intbitsmaxthenbitselsesub_big_intbitstruncmaxinlettrunc=ifge_big_intcmax||lt_big_intc(minus_big_intmax)thenifge_big_intctruncmaxthenBitTruncationelseValueTruncationelseNoTruncationintval,trunclettruncate_unsigned_cilint(c:cilint)(n:int):cilint*truncation=letmax=shift_left_big_intunit_big_int(n-1)inlettruncmax=shift_left_big_intunit_big_intninletbits=mod_big_intctruncmaxinlettrunc=ifge_big_intctruncmax||lt_big_intczero_big_inttheniflt_big_intc(minus_big_intmax)thenBitTruncationelseValueTruncationelseNoTruncationinbits,truncletis_int_cilint(c:cilint):bool=is_int_big_intc