AFIT/Source/scalable/scalable.ml

426 lines
12 KiB
OCaml

(** A naive implementation of big integers
This module aims at creating a set of big integers naively. Such data
types will be subsequently called bitarrays. A bitarray is a list of
zeros and ones ; first integer representing the sign bit. In this
context zero is reprensented by the empty list []. The list is to
be read from left to right ; this is the opposite convention to the
one you usually write binary decompositions with. After the sign bit
the first encountered bit is the coefficient in front of two to
the power zero. This convention has been chosen to ease writing
down code. A natural bitarray is understood as being a bitarray of
which you've taken out the sign bit, it is just the binary
decomposition of a non-negative integer.
*)
(** Creates a bitarray from a built-in integer.
@param x built-in integer.
*)
let sign x =
if x < 0 then
-1
else
1;;
let rec rem_rec bA =
match bA with
[] -> []
| 1::bA -> 1::bA
| _::bA -> rem_rec bA;;
let rem0_rev bA = List.rev (rem_rec bA);;
let rem0 bA =
let bA = List.rev bA
in rem0_rev bA;;
let from_int x =
if x = 0 then []
else
let rec from_int_rec n =
match n with
0 -> []
| n -> n mod 2::from_int_rec (n/2)
in let bitsign =
if sign x = -1 then
1
else
0
in bitsign::from_int_rec (sign x * x);;
(** Transforms bitarray of built-in size to built-in integer.
UNSAFE: possible integer overflow.
@param bA bitarray object.
*)
let modulo a b =
match sign a = -1 && a mod b != 0 with
true -> a mod b + b
| _ -> a mod b;;
let power x n =
if n = 0 then 1 else
let rec power_rec x1 n =
match n with
1 -> x1
| n when modulo n 2 = 0 -> power_rec (x1 * x1) (n/2)
| n -> x1 * power_rec (x1 * x1) ((n-1)/2)
in power_rec x n;;
let to_int bA =
match bA with
[] -> 0
| e::bA1 -> begin
let sign = match e with
0 -> 1
| _ -> -1
in let rec to_int_rec bA pow =
match bA with
[] -> 0
| e::bA1 -> (e * power 2 pow) + to_int_rec bA1 (pow + 1)
in sign * to_int_rec bA1 0
end;;
(** Prints bitarray as binary number on standard output.
@param bA a bitarray.
*)
let print_b bA =
match bA with
[] -> print_endline "0"
| e::l1 -> begin
let rec print_b_rec bA =
match bA with
[] -> print_endline ""
| e::l1 -> begin
print_b_rec l1;
print_int e
end
in
if e = 1 then (
print_string "-";
print_b_rec l1
) else
print_b_rec l1
end;;
(** Toplevel directive to use print_b as bitarray printer.
CAREFUL: print_b is then list int printer.
UNCOMMENT FOR TOPLEVEL USE.
*)
(* #install_printer print_b *)
(** Internal comparisons on bitarrays and naturals. Naturals in this
context are understood as bitarrays missing a bit sign and thus
assumed to be non-negative.
*)
(** Comparing naturals. Output is 1 if first argument is bigger than
second -1 if it is smaller and 0 in case of equality.
@param nA A natural, a bitarray having no sign bit.
Assumed non-negative.
@param nB A natural.
*)
let compare_n nA nB =
match (nA, nB) with
([], []) -> 0
| (_, []) -> 1
| ([], _) -> -1
| (_::nA, _::nB) ->
let nA = List.rev nA and nB = List.rev nB in
let lengthA = List.length nA and lengthB = List.length nB in
if lengthA > lengthB then
1
else if lengthA < lengthB then
-1
else
let rec compare_n_rec nA nB =
match (nA, nB) with
([], []) -> 0
| ([], _) | (0::_, 1::_) -> -1
| (_, []) | (1::_, 0::_) -> 1
| (_::l1, _::l2) -> compare_n_rec l1 l2
in compare_n_rec nA nB;;
(** Bigger inorder comparison operator on naturals. Returns true if
first argument is bigger than second and false otherwise.
@param nA natural.
@param nB natural.
*)
let (>>!) nA nB = compare_n nA nB = 1;;
(** Smaller inorder comparison operator on naturals. Returns true if
first argument is smaller than second and false otherwise.
@param nA natural.
@param nB natural.
*)
let (<<!) nA nB = compare_n nA nB = -1;;
(** Bigger or equal inorder comparison operator on naturals. Returns
true if first argument is bigger or equal to second and false
otherwise.
@param nA natural.
@param nB natural.
*)
let (>=!) nA nB =
let comp = compare_n nA nB
in comp = 1 || comp = 0;;
(** Smaller or equal inorder comparison operator on naturals. Returns
true if first argument is smaller or equal to second and false
otherwise.
@param nA natural.
@param nB natural.
*)
let (<=!) nA nB =
let comp = compare_n nA nB
in comp = -1 || comp = 0;;
(** Comparing two bitarrays. Output is 1 if first argument is bigger
than second -1 if it smaller and 0 in case of equality.
@param bA A bitarray.
@param bB A bitarray.
*)
let compare_b bA bB =
match (bA, bB) with
([], []) -> 0
| ([], _) | (1::_, 0::_) -> -1
| (_, []) | (0::_, 1::_) -> 1
| (sign:: nA, _::nB) ->
match sign with
0 -> compare_n (0::nA) (0::nB)
| _ -> -1 * compare_n (0::nA) (0::nB);;
(** Bigger inorder comparison operator on bitarrays. Returns true if
first argument is bigger than second and false otherwise.
@param nA natural.
@param nB natural.
*)
let (<<) bA bB = compare_b bA bB = -1;;
(** Smaller inorder comparison operator on bitarrays. Returns true if
first argument is smaller than second and false otherwise.
@param nA natural.
@param nB natural.
*)
let (>>) bA bB = compare_b bA bB = 1;;
(** Bigger or equal inorder comparison operator on bitarrays. Returns
true if first argument is bigger or equal to second and false
otherwise.
@param nA natural.
@param nB natural.
*)
let (<<=) bA bB =
let comp = compare_b bA bB
in comp = -1 || comp = 0;;
(** Smaller or equal inorder comparison operator on naturals. Returns
true if first argument is smaller or equal to second and false
otherwise.
@param nA natural.
@param nB natural.
*)
let (>>=) bA bB =
let comp = compare_b bA bB
in comp = 1 || comp = 0;;
(** Sign of a bitarray.
@param bA Bitarray.
*)
let sign_b bA =
match bA with
[] | 0::_ -> 1
| _ -> -1;;
(** Absolute value of bitarray.
@param bA Bitarray.
*)
let abs_b bA =
match bA with
[] -> []
| _::bA -> 0::bA;;
(** Quotient of integers smaller than 4 by 2.
@param a Built-in integer smaller than 4.
*)
let _quot_t a =
match a with
0 | 1-> 0
| _ -> 1
(** Modulo of integer smaller than 4 by 2.
@param a Built-in integer smaller than 4.
*)
let _mod_t a =
match a with
0 | 2 -> 0
| _ -> 1
(** Division of integer smaller than 4 by 2.
@param a Built-in integer smaller than 4.
*)
let _div_t a = (_quot_t a, _mod_t a);;
(** Addition of two naturals.
@param nA Natural.
@param nB Natural.
*)
let add_n nA nB =
match (nA, nB) with
(l, []) | ([], l) -> l
| (_::nA, _::nB) ->
let rec add_n_rec nA nB ret res=
match (nA, nB) with
([], []) -> ret::res
| (e::l1, []) | ([], e::l1) -> begin
let tot = e + ret in
let (q, r) = _div_t tot in
add_n_rec l1 [] q (r::res)
end
| (e1::nA, e2::nB) -> begin
let tot = e1 + e2 + ret in
let (q, r) = _div_t tot in
add_n_rec nA nB q (r::res)
end
in rem0_rev (add_n_rec nA nB 0 [0]);;
(** Difference of two naturals.
UNSAFE: First entry is assumed to be bigger than second.
@param nA Natural.
@param nB Natural.
*)
let diff_n nA nB =
let rec diff_n_rec nA nB ret res=
match (nA, nB) with
([], []) -> res
| ([], e::nB) when 0 - (ret + e) = 0 -> diff_n_rec nA nB 0 (0::res)
| ([], e::nB) when 0 - (ret + e) = -1 -> diff_n_rec nA nB 1 (1::res)
| ([], e::nB) -> diff_n_rec nA nB 1 (0::res)
| (e::nA, []) when e - ret >= 0 -> diff_n_rec nA nB 0 (e-ret::res)
| (e::nA, []) -> diff_n_rec nA nB 1 (1::res)
| (e1::nA, e2::nB) when e1 - (e2 + ret) = 0 -> diff_n_rec nA nB 0 (0::res)
| (e1::nA, e2::nB) when e1 - (e2 + ret) = 1 -> diff_n_rec nA nB 0 (1::res)
| (e1::nA, e2::nB) when e1 - (e2 + ret) = -1 -> diff_n_rec nA nB 1 (1::res)
| (_::nA, _::nB) -> diff_n_rec nA nB 1 (0::res)
in match (nA, nB) with
(l, []) -> l
| ([], _::nB) -> rem0_rev (diff_n_rec [] nB 0 [0])
| (_::nA, _::nB) -> rem0_rev (diff_n_rec nA nB 0 [0]);;
(** Shifts bitarray to the left by a given natural number.
@param bA Bitarray.
@param d Non-negative integer.
*)
let shift bA d =
match bA with
[] -> []
| sign::bA ->
let rec shift_rec bA d res=
match d with
d when d <= 0 -> res
| d -> shift_rec bA (d-1) (0::res)
in sign::shift_rec bA d bA;;
(** Addition of two bitarrays.
@param bA Bitarray.
@param bB Bitarray.
*)
let abs_neg bA =
match bA with
[] -> []
| _::bA -> 1::bA;;
let add_b bA bB =
match (bA, bB) with
([], l) | (l, []) -> l
| (0::bA, 0::bB) -> add_n (0::bA) (0::bB)
| (1::bA, 1::bB) -> abs_neg (add_n (0::bA) (0::bB))
| (1::bA, 0::bB) when (<=!) (0::bA) (0::bB) -> diff_n (0::bB) (0::bA)
| (1::bA, 0::bB) -> abs_neg (diff_n (shift [0] (List.length bA)) (diff_n (0::bB) (0::bA)))
| (0::bA, 1::bB) when (>=!) (0::bA) (0::bB) -> diff_n (0::bA) (0::bB)
| (0::bA, 1::bB) -> abs_neg (diff_n (shift [0] (List.length bB)) (diff_n (0::bA) (0::bB)))
| _ -> failwith "error";;
(** Difference of two bitarrays.
@param bA Bitarray.
@param bB Bitarray.
*)
let diff_b bA bB =
match bB with
[] -> bA
| 1::bB -> add_b bA (0::bB)
| _ -> add_b bA (abs_neg bB);;
(** Multiplication of two bitarrays.
@param bA Bitarray.
@param bB Bitarray.
*)
let mult_b bA bB =
match (bA, bB) with
([], _) | (_, []) -> []
| (signA::bA, signB::bB) ->
let rec mult_b_rec bA bB n =
match bA with
[] -> []
| e::bA ->
let a = match e with 0 -> [] | _ -> bB in
add_n (shift a n) (mult_b_rec bA bB (n+1))
in match (signA, signB) with
(0,0) | (1,1) -> abs_b (mult_b_rec bA (0::bB) 0)
| _ -> abs_neg (mult_b_rec bA (0::bB) 0)
(** Integer division of two bitarrays.
@param bA Bitarray you want to divide.
@param bB Bitarray you wnat to divide by.
*)
let div_b bA bB =
match (bA, bB) with
(_, []) -> invalid_arg "divider must be Non-Zero"
| ([],_) -> ([], [])
| (sign1::bA, sign2::bB) ->
let rec div_b_rec bA bB res=
if (>=!) bA bB then
let bA = diff_n bA bB
and res = add_n [0;1] res
in div_b_rec bA bB res
else (res, bA)
in let (quot, rest) = div_b_rec (0::bA) (0::bB) [] in
match (sign1, sign2) with
(0,0) | (1,1) -> (abs_b quot, rest)
| _ -> begin
match (quot, rest) with
(quot, []) -> (abs_neg quot, [])
| (quot, rest) -> (abs_neg (add_n [0;1] quot), diff_n (0::bB) rest)
end
(** Quotient of two bitarrays.
@param bA Bitarray you want to divide by second argument.
@param bB Bitarray you divide by. Non-zero!
*)
let quot_b bA bB =
let (quot, _) = div_b bA bB in quot;;
(** Modulo of a bitarray against a positive one.
@param bA Bitarray the modulo of which you're computing.
@param bB Bitarray which is modular base.
*)
let mod_b bA bB =
let (_, rest) = div_b bA bB in rest;;