Page 1 of 1

Simple decimal precision problem

PostPosted: Sat Sep 10, 2011 5:13 pm
by Jope
Hi

I am implementing the Gauss-Legendre algorithm for approximating pi in common lisp. How do I use a long float? I have not been using lisp for very long and it automatically uses float and prints somewhere around 10-14 digits, but I want to generate and display many more digits than that.

I keep reading (setf (EXT:LONG-FLOAT) 2000) (or something like that) for instance, but I have not been able to get this to do anything.

Re: Simple decimal precision problem

PostPosted: Sun Sep 11, 2011 1:59 am
by Ramarren
Common Lisp has no standardised functionality for that. I have never looked into that, but apparentlyCLISP has arbitrary precision floats. A solution portable between implementation would require implementing a custom numeric type.

Re: Simple decimal precision problem

PostPosted: Sun Sep 11, 2011 7:25 pm
by nuntius
CL has a few float types. The default read format can be helpful when you don't want to type an explicit 1d0. Most implementations only really support single-float and double-float. I think Scieneer had a true long-float; but it appears to no longer be active.

Re: Simple decimal precision problem

PostPosted: Mon Sep 12, 2011 7:30 pm
by Jope
Thank you for the suggestions, I forgot to mention I am using GNU common lisp 2.6.7.

My problem is really how to go about specifying that double-float should be used for the calculations. Here is the simple algorithm as I have it currently:

Code: Select all
; Computes an approximation of pi using the Gauss-Legendre method. Accuracy depending on input 'n'
; eg. (GL 8)   -> 3.141592653589794
;       (GL 30) -> 3.141592653589794

(defun GL (n)
  (GL_start 1 (/ 1 (sqrt 2)) (/ 1 4) 1 n)
)

(defun GL_start (a b y z n)
  (cond
    ((eq n 0) (/ (sq (+ a b)) (* 4 y)))
    (T (GL_start (/ (+ a b) 2) (sqrt (* a b)) (- y (* z (sq (- a (/ (+ a b) 2))))) (* 2 z) (- n 1)))
  )
)

(defun sq (x)
  (* x x)
)


As you can see in the example, GL(8) has the same number of digits as GL(30), but I would like to be able to control the number of digits displayed depending on the inputted 'n'.
Thank you

Re: Simple decimal precision problem

PostPosted: Mon Sep 12, 2011 11:48 pm
by edgar-rft
Jope wrote:My problem is really how to go about specifying that double-float should be used for the calculations.

For example use one of these:

Code: Select all
(defun GL (n)
  (GL_start 1 (/ 1 (sqrt 2.0d0)) (/ 1 4) 1 n))

(defun GL (n)
  (GL_start 1 (/ 1 (sqrt (the double-float 2.0))) (/ 1 4) 1 n))

(Edit: do not use the second version, see below for the reasons why not.)

Jope wrote:As you can see in the example, GL(8) has the same number of digits as GL(30), but I would like to be able to control the number of digits displayed depending on the inputted 'n'.

If GNU_CL uses IEEE floats (what is very likely) then you're out of luck because then the number of digits is defined by IEEE and not by GNU_CL. The only possibilies would be either to artificially cripple the floats, e.g. by:

Code: Select all
(defun digits-after-dot (float digits)
  (let ((factor (* (expt 10 digits))))
    (/ (ftruncate (* float factor)) factor)))
 
(digits-after-dot pi 3)  => 3.141
(digits-after-dot pi 4)  => 3.1415
(digits-after-dot pi 5)  => 3.14159

But this is a rather wacky hack that will quickly raise "floating point overflow" errors, and will of course not display more digits than defined by IEEE.

The only other alternative is using "bigfloats", e.g:

  • bf.lisp - Common Lisp Bigfloat Package by Richard Fateman

- edgar

Re: Simple decimal precision problem

PostPosted: Tue Sep 13, 2011 1:36 am
by Paul
edgar-rft wrote:
Code: Select all
(defun GL (n)
  (GL_start 1 (/ 1 (sqrt (the double-float 2.0))) (/ 1 4) 1 n))


Don't do this. (the double-float 2.0) doesn't make it a double, it just tells the compiler it is one -- which is a lie unless you've set *read-default-float-format* to a non-default value. (I can't see how any harm can come from this lie, except that the result won't be what you expect; in fact, the compiler should know better; but in theory it's "monkeys from the nose" code)

Re: Simple decimal precision problem

PostPosted: Tue Sep 13, 2011 2:16 am
by edgar-rft
@Jope: Paul is right, I worked too long with SBCL, where everything gets compiled before evaluation, but this trick doesn't work in all CL implementations, so it's better not to use (the double-float 2.0) with GNU_CL, where it probably doesn't work.

@Paul: thanks.

Re: Simple decimal precision problem

PostPosted: Thu Sep 22, 2011 1:14 am
by marcoxa
You may want to look at the (high quality) OCT library http://common-lisp.net/project/oct/

MA

Re: Simple decimal precision problem

PostPosted: Thu Sep 22, 2011 11:13 pm
by Konfusius
Format allows you to control the number of digits printed by the format string "~0,<n>E" where <n> is the number of digits.

Code: Select all
(defun print-float (f &optional (n 0))
  (format t (format nil "~~0,~DE" n) f))