I am trying to convert a large base-10 number to base-16 and then to hex. The error I am getting is OCaml is saying the integer is too big.
# let large_int = 11515195063862318899931685488813747395775516287289682636499965282714637259206269 ;;
Error: Integer literal exceeds the range of representable integers of type int
I tried using Int64 as well and a similar issue.
# let large_int = Int64.of_string "11515195063862318899931685488813747395775516287289682636499965282714637259206269";;
Exception: Failure "Int64.of_string".
This is the larger code I am trying to make work. It works as expected with the example integer below.
(* convert from base10_to_base16 *)
let rec split_digits n =
if n = 0 then [] else
let (d, rest) = n mod 256, n / 256 in
d :: split_digits rest
let decode_base10 message =
let bytes_arr = List.rev (split_digits message) in
let decoded_message = String.concat "" (List.map (fun x -> String.make 1 (Char.chr x)) bytes_arr) in
decoded_message
let base10_message = 310400273487 (* base-10 number *)
let decoded_message = decode_base10 base10_message
You'll want to install the Zarith library for working with arbitrary precision numbers, since the native integer types cannot handle the size numbers you're asking them to.
Your split_digits
function is then pretty straightforward to implement, using functions like Z.div
and Z.rem
in place of int
operations /
and mod
.
# #require "zarith";;
# let n = Z.of_string "11515195063862318899931685488813747395775516287289682636499965282714637259206269";;
val n : Z.t = <abstr>
# let rec split_digits n =
if n = Z.zero then []
else
let z256 = Z.of_int 256 in
Z.to_int (Z.rem n z256) :: split_digits (Z.div n z256);;
val split_digits : Z.t -> int list = <fun>
# split_digits n;;
- : int list =
[125; 110; 119; 48; 100; 95; 121; 52; 119; 95; 51; 104; 55; 95;
108; 108; 52; 95; 54; 110; 49; 100; 48; 99; 110; 51; 123; 111;
116; 112; 121; 114; 99]
Of course, you may want to make your split_digits
function tail-recursive to avoid any chance of a stack overflow on especially enormous numbers. Easily accomplished with tail_mod_cons
.
let[@tail_mod_cons] rec split_digits n =
if n = Z.zero then []
else
let z256 = Z.of_int 256 in
Z.to_int (Z.rem n z256) :: split_digits (Z.div n z256)
Of course, the same might be accomplished by adapting split_digits
to generate a sequence. I'll also make the 256 a parameter for added flexibility.
# let rec split_digits sz n () =
let open Z in
if n = zero then Seq.Nil
else
let z_sz = of_int sz in
Seq.Cons (
to_int @@ rem n z_sz,
split_digits sz @@ div n z_sz
);;
val split_digits : Z.t -> int -> int Seq.t = <fun>
# n
|> split_digits 256
|> List.of_seq;;
- : int list =
[125; 110; 119; 48; 100; 95; 121; 52; 119; 95; 51; 104; 55; 95;
108; 108; 52; 95; 54; 110; 49; 100; 48; 99; 110; 51; 123; 111;
116; 112; 121; 114; 99]