Skip to content

OCaml pidigits update

CONTRIBUTE SOURCE CODE

(*
 * The Computer Language Benchmarks Game 
 * https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
 *
 * prepared by Gabriel Scherer
 * inspired by Zarith version (OCaml#5) by Christophe Troestler and Matías Giovannini
 *)

let init = (Mpz.of_int 1, Mpz.of_int 1, Mpz.of_int 0)

let extract =
  let res : Mpz.m Mpz.tt = Mpz.init () in
  fun (num,den,acc) nth ->
    (* (nth * num + acc) / den |> to_int *)
    Mpz.mul_si res num nth;
    Mpz.add res res acc;
    Mpz.tdiv_q res res den;
    Mpz.get_int res

let next z = extract z 3

let safe z n = extract z 4 = n

let prod =
  let tmp : Mpz.m Mpz.tt = Mpz.init () in
  fun (res_num, res_den, res_acc) (num,den,acc) d ->
    (* (10 * num, den, 10 * (acc - den * of_int d)) *)
    Mpz.mul_si res_num num 10;

    Mpz.set res_den den;

    Mpz.mul_si tmp den d;
    Mpz.sub res_acc acc tmp;
    Mpz.mul_si res_acc res_acc 10;

    ()

let cons =
  fun (res_num, res_den, res_acc) (num,den,acc) k ->
    let k2 = k * 2 + 1 in
    (*  (k * num, k2 * den,  k2 * (acc + num + num)) *)
    Mpz.mul_si res_den den k2;

    Mpz.add res_acc acc num;
    Mpz.add res_acc res_acc num;
    Mpz.mul_si res_acc res_acc k2;

    (* must go below the computation of res_acc,
       to avoid trashing the 'num' value it uses *)
    Mpz.mul_si res_num num k;

    ()

let columns = 10

let rec digit k z n row col =
  if n = 0 then Printf.printf "%*s\t:%i\n" (columns-col) "" (row+col) else
  let d = next z in
  if safe z d then
    if col = columns then begin
      let row = row + col in
      Printf.printf "\t:%i\n%i" row d;
      prod z z d;
      digit k z (n-1) row 1
    end else begin 
      print_int d;
      prod z z d;
      digit k z (n-1) row (col+1)
    end
  else begin
    cons z z k;
    digit (k+1) z n row col
  end

let digits n = digit 1 init n 0 0

let () = digits (try int_of_string (Array.get Sys.argv 1) with _ -> 27)

Provide a helpful Title

OCaml pidigits Gabriel Scherer

Attach your source code file

pidigits.ocaml-6.ml

Provide an example build command-line

The command-line that I used to build and test my program is:

opam install mlgmpidl (* to get the Mpz module *)
ocamlfind ocamlopt -package gmp -linkpkg pidigits.ocaml-6.ml -o pidigits.ocaml-6.ocaml_run
time ./pidigits.ocaml-6.ocaml_run 10_000

However, I am not sure whether opam is available on your test environment. I suppose that you prefer to use Debian packages to install the dependencies. The packaging of mlgmpidl on Debian is a bit funky, it is included in the larger package libapron-ocaml-dev. I think that the following should work, but I have not tested it (no Debian machine at hand). Please let me know if you don't want external dependencies, or if the command does not work.

apt-get install libapron-ocaml-dev
ocamlopt -I /usr/lib/ocaml/apron gmp.cmxa pidigits.ocaml-6.ml -o pidigits.ocaml-6.ocaml_run

Thanks!