
(*s Test program for [Creal]. *)

open Printf
open Gmp
open Creal

(*s Options *)

let prec = ref 50
let display = ref true
let sanity_check = ref true

let _ = 
  Arg.parse 
      ["-p", Arg.Int ((:=) prec), "-p n  set the precision";
       "-silent", Arg.Clear display, "-silent  no display";
       "-check", Arg.Set sanity_check, "-check  only sanity checks" ]
      (fun s -> raise (Arg.Bad ("unknown option " ^ s)))
      "test [-p prec] [silent]"

(*s Sanity checks. Compare two numbers up to the precision. *)

let _ = 
  if !sanity_check then begin 
    printf "*** Sanity checks ***\n\n"; flush stdout
  end

let check msg x y =
  if !sanity_check then begin
    printf "%s... " msg; flush stdout;
    let delta = Z.sub (approx x !prec) (approx y !prec) in
    if Z.cmp_si (Z.abs delta) 1 <= 0 then 
      printf "ok\n\n"
    else begin
      printf "FAILED!\n\n"; exit 1
    end;
    flush stdout
  end

let sqrt_2 = sqrt two

let _ = check "sqrt(2)^2 = 2" (sqrt_2 *! sqrt_2) two

let _ = check "1/sqrt(2) = sqrt(2)/2" (inv sqrt_2) (sqrt_2 /! two)

let sqrt_3 = sqrt (of_int 3)

let _ = check "1 = (sqrt(3) + sqrt(2)) * (sqrt(3) - sqrt(2))"
	  one ((sqrt_3 +! sqrt_2) *! (sqrt_3 -! sqrt_2))

let _ = check "(sqrt(2) ^ sqrt(2)) ^ sqrt(2) = 2"
	  (pow (pow sqrt_2 sqrt_2) sqrt_2) two

let one_third = of_q (Q.from_ints 1 3)
let root3 x = pow x one_third

let _ = check "54^1/3 - 2^1/3 = 16^1/3" 
	  (root3 (of_int 54) -! root3 two) (root3 (of_int 16))

let _ = check "cos(0)=1" (cos zero) one
let _ = check "cos(pi/2)=0" (cos pi_over_2) zero
let _ = check "sin(0)=0" (sin zero) zero
let _ = check "sin(pi/2)=1" (sin pi_over_2) one

let pi_over_4 = pi /! (of_int 4)
let square x = x *! x
let _ = check "cos^2(pi/4) + sin^2(pi/4) = 1"
	  (square (cos pi_over_4) +! square (sin pi_over_4)) one

let _ = check "tan(pi/4) = 1" (tan pi_over_4) one

let _ = check "pi/4 = 4arctan(1/5) - arctan(1/239)" pi_over_4 
	  (of_int 4 *! arctan_reciproqual 5 -! arctan_reciproqual 239)

let _ = check "ln(1) = 0" (ln one) zero

let _ = check "ln(e) = 1" (ln e) one

let _ = check "ln(pi*pi) = 2ln(pi)" (ln (square pi)) (two *! ln pi)

let _ = check "exp(-pi) = exp(-pi/2) * exp(-pi/2)"
	  (exp (neg pi)) (let y = exp (neg pi_over_2) in y *! y)

let _ = if !sanity_check then exit 0


(*s Benchmark. *)

(* Test function: display the real number, if not [silent] ; otherwise, 
   just compute the approximation (for timings). *)

let _ = printf "\n*** Benchmarks ***\n\n"; flush stdout

let test msg beautiful x =
  if !display then begin
    printf "%s = " msg; flush stdout;
    printf "%s\n\n"
      (if beautiful then to_beautiful_string x !prec else to_string x !prec);
    flush stdout
  end else begin
    printf "%s\n" msg;
    flush stdout;
    ignore (approx x !prec)
  end

(*s golden ratio *)
let phi = (one +! sqrt (of_int 5)) /! (of_int 2)
let _ = test "golden ratio" true phi

(* e (predefined in [Creal]) *)
let _ = test "e" true e

(* pi (predefined in [Creal]) *)
let _ = test "pi" true pi

(*s The Exact Arithmetic Competition: Level 0 Tests 
   http://www.cs.man.ac.uk/arch/dlester/arithmetic/level0t.html *)

(* sqrt(pi) *)
let _ = test "sqrt(pi)" false (sqrt pi)

(* sin(exp(1)) *)
let _ = test "sin(e)" false (sin e)

(* cos(exp(1)) *)
let _ = test "cos(e)" false (cos e)

(* sin(sin(sin(1))) *)
let x = sin (sin (sin one))
let _ = test "sin(sin(sin(1)))" false x

(* cos(cos(cos(1))) *)
let x = cos (cos (cos one))
let _ = test "cos(cos(cos(1)))" false x

(* exp(exp(exp(1))) *)
let x = exp (exp (exp one))
let _ = test "exp(exp(exp(1)))" false x

(* log(pi) *)
let _ = test "ln(pi)" false (ln pi)

(* log(1+log(1+log(1+pi))) *)
let ln_ln_ln_pi = ln (one +! ln (one +! ln (one +! pi)))
let _ = test "ln(1+ln(1+ln(1+pi)))" false ln_ln_ln_pi

(* log(1+log(1+log(1+exp(1)))) *)
let ln_ln_ln_e = ln (one +! ln (one +! ln (one +! e)))
let _ = test "ln(1+ln(1+ln(1+e)))" false ln_ln_ln_e

(*i
(* log(1+log(1+log(1+log(1+log(1+log(1+pi)))))) *)
let x = ln (one +! ln (one +! ln (one +! ln_ln_ln_pi)))
let _ = test "ln(1+ln(1+ln(1+ln(1+ln(1+ln(1+pi))))))" false x

(* log(1+log(1+log(1+log(1+log(1+log(1+exp(1))))))) *)
let x = ln (one +! ln (one +! ln (one +! ln_ln_ln_e)))
let _ = test "ln(1+ln(1+ln(1+ln(1+ln(1+ln(1+e))))))" false x
i*)

(* sin(1e50) *)
let ten_to_50 = pow_int (of_int 10) 50
let x = sin ten_to_50
let _ = test "sin(1e50)" false x

(* cos(1e50) *)
let x = cos ten_to_50
let _ = test "cos(1e50)" false x

(* arctan(1) *)
let _ = test "arctan(1)" false (arctan one)

(*i

(* BUG GMP 2 *)
let q = 
  Q.from_zs (Z.from_int 1) (Z.from_string "19807040628566084398385987584" 10)
let _ = Q.add q (Q.from_ints 1 2)

(* BUG GMP 3 *)
let q = Q.from_zs (Z.from_string "112803124130337404998606757686274889113032882986303222429756948481" 10) (Z.from_string "5192296858534827628530496329220096" 10)
let q' = Q.add q (Q.from_ints 1 2)
let _ = Z.fdiv_q (Q.get_num q') (Q.get_den q')

let time f x = 
  let old = Sys.time () in 
  let y = f x in 
  Printf.printf "%f\n" (Sys.time () -. old); 
  y
;;

i*)
