Я пытаюсь преобразовать большое число с основанием 10 в число с основанием 16, а затем в шестнадцатеричное. Ошибка, которую я получаю, заключается в том, что OCaml говорит, что целое число слишком велико.
# let large_int = 11515195063862318899931685488813747395775516287289682636499965282714637259206269 ;;
Error: Integer literal exceeds the range of representable integers of type int
Я также пробовал использовать Int64 и аналогичную проблему.
# let large_int = Int64.of_string "11515195063862318899931685488813747395775516287289682636499965282714637259206269";;
Exception: Failure "Int64.of_string".
Это более крупный код, который я пытаюсь заставить работать. Это работает, как и ожидалось, с примером целого числа ниже.
(* 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
Вам понадобится установить библиотеку Zarith для работы с числами произвольной точности, поскольку собственные целочисленные типы не могут обрабатывать числа размера, которые вы им запрашиваете.
Тогда вашу функцию split_digits
довольно просто реализовать, используя такие функции, как Z.div и Z.rem вместо операций int
/
и 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]
Конечно, вы можете захотеть сделать функцию split_digits
хвостовой рекурсивной, чтобы избежать вероятности переполнения стека при работе с особенно огромными числами. Это легко сделать с помощью 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)
Конечно, того же можно добиться, адаптировав split_digits
для создания последовательности . Я также сделаю 256 параметром для большей гибкости.
# 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]