123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183(*
* BatInt32 - Extended Big integers
* Copyright (C) 2007 Bluestorm <bluestorm dot dylc on-the-server gmail dot com>
* 2008 David Teller
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)letbig_int_base_default_symbols=letsymboloffsetbasek=char_of_int(k-offset+(int_of_charbase))inBatBytesCompat.string_init(10+26*2)(funk->ifk<10thensymbol0'0'kelseifk<36thensymbol10'a'kelsesymbol 36'A'k)letto_string_in_custom_basesymbols(* vector of digit symbols 0,1,...,a,b,... *)b(* base, int > 1and <= number of defined symbols *)n(* big integer *)=letopenBig_intinifb<=1theninvalid_arg"Big_int.to_string_in_custom_base: base must be > 1";ifb>String.lengthsymbolstheninvalid_arg("Big_int.to_string_in_custom_base: big_int_base_default_symbols too small for base "^(string_of_intb)^":only "^string_of_int(String.lengthsymbols));letisnegative =sign_big_int n<0in(* generouslyover-approximate number of binary digits of n;
num_digits_big_int actually returns the number of _words_ *)letbase2digits=Sys.word_size*num_digits_big_intnin(* over-approximate resulting digits in base b, using following theorem,
where k = base2digits :
k k k * Log[2]
digits in base b <= Ceiling[Log[b, 2 ]] and Log[b, 2 ] == -----------
Log[b] *)letbasebdigits=int_of_float(ceil(((float_of_int base2digits)*.(log2.))/.(log(float_of_intb))))+(ifisnegative then1else0)(* the pesky '-' sign *)inletbuff=Bytes.createbasebdigitsin(* we know the buffer is large enough *)letcurr=ref(basebdigits-1)andcount=ref0inletaddcharc=Bytes.setbuff!currc;incrcount;decr currin(* switch base to big int representation and n to mutable, and loop *)letb=big_int_of_intbandn=ref(abs_big_int n)inwhile compare_big_int !nb>=0doletq,d=quomod_big_int!nbinn:=q;addcharsymbols.[int_of_big_intd];done;addcharsymbols.[int_of_big_int!n];ifisnegativethenaddchar'-';Bytes.sub_stringbuff(!curr+1)!countletto_string_in_basebn=ifb<=1||b>36theninvalid_arg"Big_int.to_string_in_base: base must be in 2..36"elseto_string_in_custom_basebig_int_base_default_symbolsbnletto_string_in_binary=to_string_in_base2letto_string_in_octal=to_string_in_base8letto_string_in_hexa=to_string_in_base16(*$= to_string_in_base & ~printer:identity
(to_string_in_base 16 (big_int_of_int 9485)) "250d"
(to_string_in_base 16 (big_int_of_int (-9485))) "-250d"
(to_string_in_base 10 (big_int_of_int 9485)) "9485"
(to_string_in_base 8 (big_int_of_int 9485)) "22415"
(to_string_in_base 2 (big_int_of_int 9485)) "10010100001101"
(to_string_in_base 36 (big_int_of_int 948565)) "kbx1"
(to_string_in_base 3 (big_int_of_int 2765353)) "12012111100111"
*)(*$= to_string_in_custom_base & ~printer:identity
(to_string_in_custom_base "*/!" 3 (big_int_of_int 2765353)) "/!*/!////**///"
*)(*$= to_string_in_binary & ~printer:identity
(to_string_in_binary (big_int_of_int 9485)) "10010100001101"
*)(*$= to_string_in_octal & ~printer:identity
(to_string_in_octal (big_int_of_int 9485)) "22415"
*)(*$= to_string_in_hexa & ~printer:identity
(to_string_in_hexa (big_int_of_int 9485)) "250d"
*)(*$T to_string_in_base
try ignore (to_string_in_base 37 (big_int_of_int 948565)); false \
with Invalid_argument _ -> true
try ignore (to_string_in_base 1 (big_int_of_int 948565)); false \
with Invalid_argument _ -> true
*)(*$Q to_string_in_base
Q.int (fun i-> let bi = big_int_of_int i in \
to_string_in_base 10 bi = string_of_big_int bi)
*)openBatNumbermoduleBaseBig_int:NUMERIC_BASEwithtypet=Big_int.big_int =structopenBig_inttypet=big_intletzero=zero_big_intletone=unit_big_intletsucc=succ_big_intletpred=pred_big_intletneg=minus_big_intletabs=abs_big_intletadd =add_big_intletsub =sub_big_intletmul =mult_big_intletdiv=div_big_intletmodulo=mod_big_intletpow=power_big_int_positive_big_intletto_string=string_of_big_intlet of_string=big_int_of_stringlet to_int=int_of_big_intlet of_int=big_int_of_intletcompare=compare_big_intletof_floatf=tryof_string(Printf.sprintf"%.0f"f)withFailure _->invalid_arg"Big_int.of_float"(*$T of_float
to_int (of_float 4.46) = 4
to_int (of_float 4.56) = 5
to_int (of_float (-4.46)) = -4
to_int (of_float (-4.56)) = -5
try ignore (of_float nan); false with Invalid_argument _ -> true
try ignore (of_float (1. /. 0.)); false with Invalid_argument _ -> true
try ignore (of_float (-1. /. 0.)); false with Invalid_argument _ -> true
*)letto_float=float_of_big_intendincludeBig_intincludeMakeNumeric(BaseBig_int)letprintoutt=BatIO.nwriteout(to_string t)(*$T print
BatIO.to_string print (of_int 456) = "456"
BatIO.to_string print (power_int_positive_int 10 31) = "10000000000000000000000000000000"
BatIO.to_string print (power_int_positive_int (-10) 31) = "-10000000000000000000000000000000"
*)(* Tests for infix operators. Those are a little trickier than usual
* for big_ints because the generic comparison functions do not work
* for big_ints and therefore we have to take care the proper ones are
* used. Cf issue #674. Same reason prevent qcheck to compare big_ints
* so we convert to int: *)(*$< Infix *)(*$= (--) & ~printer:(IO.to_string (List.print Int.print))
((of_int 1 -- of_int 3) /@ to_int |> List.of_enum) [1; 2; 3]
*)(*$= (---) & ~printer:(IO.to_string (List.print Int.print))
((of_int 1 --- of_int 3) /@ to_int |> List.of_enum) [1; 2; 3]
((of_int 3 --- of_int 1) /@ to_int |> List.of_enum) [3; 2; 1]
*)(*$>*)##V<4.5##letbig_int_of_string_opts=trySome(big_int_of_strings)with_->None##V<4.5##letint_of_big_int_optn=trySome(int_of_big_intn)with_->None##V<4.5##letint32_of_big_int_optn=trySome(int32_of_big_intn)with_->None##V<4.5##letint64_of_big_int_optn=trySome(int64_of_big_intn)with_->None##V<4.5##letnativeint_of_big_int_optn=trySome(nativeint_of_big_intn)with_->None