I'm doing an exercise where I need to convert int to bignum in OCaml, for example:
123456789 -> {neg:false; coeffs:[123;456;789]}
There were a lot of things going inside my head when writing the function, and it was a load of fun. However, I'm not really sure if this is the cleanest, and fastest way to do this.
type bignum = {neg: bool; coeffs: int list};;
let base = 1000;;
let fromInt (n: int) : bignum =
let rec aux num:int list=
if num==0 then
[]
else
abs (num mod base) :: aux (num/base)
in
{neg=n<0; coeffs=List.rev (aux n)}
;;
fromInt turns an int to a bignum. Things to note:
- I decided to mod the number with the base, and then divide the number by the base and use that as the input. This is so I can avoid having to do exponents on ints. Was actually pretty excited when I realized that.
- Used abs on (num mod base) every recursive call. Do you think there is a cleaner way of doing this? The the reason I didn't
absit on the first call was because(-max_int) <> min_int - As you can see I'm using List.rev because I do it in reverse order. This is so I can avoid having snoc lists. I'm not really sure if it's the only way though so feel free to note me.
And here is toInt, which turns a bignum into an int.
let toInt (b: bignum) =
let rec aux (b:int list) (p:int)=
match b with
|hd::[]-> Some (hd*p)
|hd::tl-> (match aux tl (p*base) with
|Some c-> let bint = (hd*p) in
if bint < hd then None
else Some (bint+c)
|None -> None)
|[]->Some 0
in
let {neg=n; coeffs=x} = b in
let c = List.rev x in
match aux c 1 with
|Some c-> if n then Some (-c) else Some c
|None -> None
;;
I'm particularly not fond of the nested match statements, and there is probably still room for cleanup. Is there?