This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Simple decimal precision problem

9 posts · 4495 views

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

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

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

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:
; 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

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:
(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:
(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

Last edited by edgar-rft on , edited 1 time in total.

Re: Simple decimal precision problem

edgar-rft wrote:
(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

@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

Format allows you to control the number of digits printed by the format string "~0,<n>E" where <n> is the number of digits.
(defun print-float (f &optional (n 0))
  (format t (format nil "~~0,~DE" n) f))