caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Christophe TROESTLER <Christophe.Troestler@umh.ac.be>
To: "O'Caml Mailing List" <caml-list@inria.fr>
Subject: Num.quo_num
Date: Sun, 13 Feb 2005 19:24:10 +0100 (CET)	[thread overview]
Message-ID: <20050213.192410.61034584.Christophe.Troestler@umh.ac.be> (raw)

[-- Attachment #1: Type: Text/Plain, Size: 958 bytes --]

Hi,

Attached are two implementations of the algorithm for finding the
digits of pi described here:
http://web.comlab.ox.ac.uk/oucl/work/jeremy.gibbons/publications/spigot.pdf
The two implementations differ only by the fact that the first one
uses Big_int while the second one uses Num.  However, the efficiency
figures are rather different (here for 100 digits) :

Big_int
  real    0m0.009s
  user    0m0.007s
  sys     0m0.003s

Num
  real    0m0.487s
  user    0m0.484s
  sys     0m0.000s

Upon investigation, it appears that the culpright is the following:

  let quo_num x y = floor_num (div_num x y)

Indeed "Num.div_num" calls "Num.num_of_ratio" wich in turn calls
"Ratio.normalize_ratio" which I guess accounts for the huge time
difference.  Now, "Num.normalize_ratio" is actually useless for
"quo_num", since it does "num_of_big_int" anyway.  What about writing
a specialized and vastly more efficient implementation for "quo_num"?

Regards,
ChriS

[-- Attachment #2: pidigits.ml --]
[-- Type: Text/Plain, Size: 1498 bytes --]

(* Pi digits computed with the sreaming algorithm given on pages 4, 6
   & 7 of "Unbounded Spigot Algorithms for the Digits of Pi", Jeremy
   Gibbons, August 2004.  *)

open Printf
open Big_int

let ( !$ ) = Big_int.big_int_of_int
let ( +$ ) = Big_int.add_big_int
let ( *$ ) = Big_int.mult_big_int
let ( =$ ) = Big_int.eq_big_int
let zero = Big_int.zero_big_int
and one  = Big_int.unit_big_int
and three = !$ 3
and four = !$ 4
and ten  = !$ 10
and neg_ten = !$(-10)

(* Linear Fractional (aka Möbius) Transformations *)
module LFT =
struct
  let floor_ev (q,r,s,t) x = div_big_int (q *$ x +$ r) (s *$ x +$ t)

  let unit = (one, zero, zero, one)

  let comp (q,r,s,t) (q',r',s',t') =
    (q *$ q' +$ r *$ s',  q *$ r' +$ r *$ t',
     s *$ q' +$ t *$ s',  s *$ r' +$ t *$ t')
end

let next z = LFT.floor_ev z three
and safe z n = (n =$ LFT.floor_ev z four)
and prod z n = LFT.comp (ten, neg_ten *$ n, zero, one) z
and cons z k =
  let den = 2*k+1 in LFT.comp z (!$ k, !$(2*den), zero, !$ den)

let rec digit k z n row col =
  if n > 0 then
    let y = next z in
    if safe z y then
      if col = 10 then (
	let row = row + 10 in
	printf "\t:%i\n%s" row (string_of_big_int y);
	digit k (prod z y) (n-1) row 1
      )
      else (
	print_string(string_of_big_int y);
	digit k (prod z y) (n-1) row (col+1)
      )
    else digit (k+1) (cons z k) n row col
  else
    printf "%*s\t:%i\n" (10 - col) "" (row + col)

let digits n = digit 1 LFT.unit n 0 0

let () =
  digits(int_of_string Sys.argv.(1))

[-- Attachment #3: pidigits-num.ml --]
[-- Type: Text/Plain, Size: 1375 bytes --]

(* Pi digits computed with the sreaming algorithm given on pages 4, 6
   & 7 of "Unbounded Spigot Algorithms for the Digits of Pi", Jeremy
   Gibbons, August 2004.  *)

open Printf
open Num

let zero = num_of_int 0
and one  = num_of_int 1
and three = num_of_int 3
and four = num_of_int 4
and ten  = num_of_int 10
and neg_ten = num_of_int(-10)

(* Linear Fractional Transformation *)
module LFT =
struct
  let floor_ev (q,r,s,t) x = quo_num (q */ x +/ r) (s */ x +/ t)

  let unit = (one, zero, zero, one)

  let comp (q,r,s,t) (q',r',s',t') =
    (q */ q' +/ r */ s',  q */ r' +/ r */ t',
     s */ q' +/ t */ s',  s */ r' +/ t */ t')
end

let next z = LFT.floor_ev z three
and safe z n = (n =/ LFT.floor_ev z four)
and prod z n = LFT.comp (ten, neg_ten */ n, zero, one) z
and cons z k =
  let den = 2*k+1 in
  LFT.comp z (num_of_int k, num_of_int(2*den), zero, num_of_int den)

let rec digit k z n row col =
  if n > 0 then
    let y = next z in
    if safe z y then
      if col = 10 then (
	let row = row + 10 in
	printf "\t:%i\n%s" row (string_of_num y);
	digit k (prod z y) (n-1) row 1
      )
      else (
	print_string(string_of_num y);
	digit k (prod z y) (n-1) row (col+1)
      )
    else digit (k+1) (cons z k) n row col
  else
    printf "%*s\t:%i\n" (10 - col) "" (row + col)

let digits n = digit 1 LFT.unit n 0 0

let () =
  digits(int_of_string Sys.argv.(1))

                 reply	other threads:[~2005-02-13 19:05 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20050213.192410.61034584.Christophe.Troestler@umh.ac.be \
    --to=christophe.troestler@umh.ac.be \
    --cc=caml-list@inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).