Discussion:
Divide and print with precision
Marek Kubica
2014-10-15 09:22:11 UTC
Permalink
Hello,

I've got this short program here:

let prec = 1_000_000
let max_n = 205_211
let to_string = Gmp.F.to_string_base_digits ~base:10 ~digits:0

let euler_fraction n =
let open Z in
let numerator = ref one in
let denominator = ref one in
for i = 1 to n do
numerator := succ (!numerator * (of_int i));
denominator := (of_int i) * !denominator;
done;
(!numerator, !denominator)

let f () =
let (num, den) = euler_fraction max_n in
let znum = Gmp.F.from_string (Z.to_string num) in
let zden = Gmp.F.from_string (Z.to_string den) in
let euler = Gmp.F.div_prec ~prec znum zden in
print_endline @@ to_string euler

let () = f ()

It just computes e, using Zarith and Gmp. While Zarith works splendid,
I am having problems getting the division to work. I mean, it does
work, but I don't know how precise it is, because I can't get mlgmp to
print the 1_000_000 digits. From what I read in the GMP docs, 0 digits
means "whatever precision is available" but even if I explicitly
specify 1000 digits or so, the output is always
"2.718281828459045235360287471352662497757E0".

What can I do to get longer output? I don't insist on mlgmp (in fact,
it leaks memory like crazy, before I used Zarith I used mlgmp which
used 12 GB of RAM before I killed it), I just want some way to get a
base-10 floating point representation of my number.

Hope someone knows a solution.

regards,
Marek
--
Caml-list mailing list. Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
Drup
2014-10-15 10:41:12 UTC
Permalink
Why do you use Gmp ? Zarith already uses GMP under the hood and you can
use the Q module for arbitrary precision rationals.
Post by Marek Kubica
Hello,
let prec = 1_000_000
let max_n = 205_211
let to_string = Gmp.F.to_string_base_digits ~base:10 ~digits:0
let euler_fraction n =
let open Z in
let numerator = ref one in
let denominator = ref one in
for i = 1 to n do
numerator := succ (!numerator * (of_int i));
denominator := (of_int i) * !denominator;
done;
(!numerator, !denominator)
let f () =
let (num, den) = euler_fraction max_n in
let znum = Gmp.F.from_string (Z.to_string num) in
let zden = Gmp.F.from_string (Z.to_string den) in
let euler = Gmp.F.div_prec ~prec znum zden in
let () = f ()
It just computes e, using Zarith and Gmp. While Zarith works splendid,
I am having problems getting the division to work. I mean, it does
work, but I don't know how precise it is, because I can't get mlgmp to
print the 1_000_000 digits. From what I read in the GMP docs, 0 digits
means "whatever precision is available" but even if I explicitly
specify 1000 digits or so, the output is always
"2.718281828459045235360287471352662497757E0".
What can I do to get longer output? I don't insist on mlgmp (in fact,
it leaks memory like crazy, before I used Zarith I used mlgmp which
used 12 GB of RAM before I killed it), I just want some way to get a
base-10 floating point representation of my number.
Hope someone knows a solution.
regards,
Marek
--
Caml-list mailing list. Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
Marek Kubica
2014-10-15 11:13:21 UTC
Permalink
Hello,

On Wed, 15 Oct 2014 12:41:12 +0200
Post by Drup
Why do you use Gmp ? Zarith already uses GMP under the hood and you
can use the Q module for arbitrary precision rationals.
Yes, but I couldn't find a way to print Q.t types as base 10 floating
point approximations with a certain precision.

let third = Q.(//) 1 3;;
hypothetical_print_function ~precision:1000 third;;
0.33333…33333

It might well be that I am completely overlooking something, I'm happy
if someone points me to it.

regards,
Marek
--
Caml-list mailing list. Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
Török Edwin
2014-10-15 20:25:49 UTC
Permalink
Post by Marek Kubica
Hello,
let prec = 1_000_000
Do you mean this to be bits or digits?
AFAICT the ~prec in Gmp refers to bits.
Post by Marek Kubica
let max_n = 205_211
let to_string = Gmp.F.to_string_base_digits ~base:10 ~digits:0
let euler_fraction n =
let open Z in
let numerator = ref one in
let denominator = ref one in
for i = 1 to n do
numerator := succ (!numerator * (of_int i));
denominator := (of_int i) * !denominator;
done;
(!numerator, !denominator)
let f () =
let (num, den) = euler_fraction max_n in
let znum = Gmp.F.from_string (Z.to_string num) in
let zden = Gmp.F.from_string (Z.to_string den) in
This uses Gmp.default_prec (120 bits by default) for the conversion.

So if you want to use Gmp.F I think you have to specify the ~prec otherwise you might loose digits in the znum or zden conversion already:

let znum = Gmp.F.from_string_prec_base ~prec ~base:10 (Z.to_string num) in
let zden = Gmp.F.from_string_prec_base ~prec ~base:10 (Z.to_string den) in
let f = Gmp.F.div_prec ~prec znum zden in
Gmp.F.to_string_base_digits ~base:10 ~digits:0 f

Another possibility is to use from_q_prec. I would've used Gmp.Q.from_q_prec except for some odd reason it takes a Z.t instead of a Q.t,
so here is the code that uses Gmp.FR.from_q_prec:

let string_of_q_prec num den =
let znum = Gmp.Z.from_string (Z.to_string num) in
let zden = Gmp.Z.from_string (Z.to_string den) in
let f = Gmp.FR.from_q_prec ~prec ~mode (Gmp.Q.from_zs znum zden) in
Gmp.FR.to_string_base_digits ~mode ~base:10 ~digits:0 f

I don't really like going through string to convert from Z.t to Gmp.Z.t, there ought to be a more efficient way.

There is also Num.approx_num_fix, but if you already use Zarith/Gmp you probably don't want that.

Best regards,
--Edwin
--
Caml-list mailing list. Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
Marek Kubica
2014-10-20 21:16:25 UTC
Permalink
Hello Török,

Sorry, I somehow missed your reply.

On Wed, 15 Oct 2014 23:25:49 +0300
Post by Török Edwin
This uses Gmp.default_prec (120 bits by default) for the conversion.
So if you want to use Gmp.F I think you have to specify the ~prec
otherwise you might loose digits in the znum or zden conversion
let znum = Gmp.F.from_string_prec_base ~prec ~base:10 (Z.to_string
num) in let zden = Gmp.F.from_string_prec_base ~prec ~base:10
(Z.to_string den) in let f = Gmp.F.div_prec ~prec znum zden in
Gmp.F.to_string_base_digits ~base:10 ~digits:0 f
Another possibility is to use from_q_prec. I would've used
Gmp.Q.from_q_prec except for some odd reason it takes a Z.t instead
let string_of_q_prec num den =
let znum = Gmp.Z.from_string (Z.to_string num) in
let zden = Gmp.Z.from_string (Z.to_string den) in
let f = Gmp.FR.from_q_prec ~prec ~mode (Gmp.Q.from_zs znum zden) in
Gmp.FR.to_string_base_digits ~mode ~base:10 ~digits:0 f
Thank you, that worked and outputs a lot of digits which is "good
enough" for me. Great!

For the record, here's the complete program:

let prec = 1_000_000
let max_n = 205_211
let mode = Gmp.GMP_RNDN

let euler_fraction n =
let open Z in
let numerator = ref one in
let denominator = ref one in
for i = 1 to n do
numerator := succ (!numerator * (of_int i));
denominator := (of_int i) * !denominator;
done;
(!numerator, !denominator)

let f () =
let (num, den) = euler_fraction max_n in
let znum = Gmp.Z.from_string @@ Z.to_string num in
let zden = Gmp.Z.from_string @@ Z.to_string den in
let euler = Gmp.FR.from_q_prec ~mode ~prec @@ Gmp.Q.from_zs znum zden
in
print_endline @@ Gmp.FR.to_string_base_digits ~mode ~base:10
~digits:0 euler

let () = f ()
Post by Török Edwin
I don't really like going through string to convert from Z.t to
Gmp.Z.t, there ought to be a more efficient way.
Neither do I, but I suppose I'd need a C stub to take the Z.t value
(which if I understand Zarith correctly can be a GMP value, but for
small values isn't) and convert it into a Gmp.Z.t. But for such a
simple program and a constant amount of conversions, its not really
worth it.

regards,
Marek
--
Caml-list mailing list. Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs
Loading...