Simple decimal precision problem

Discussion of Common Lisp

Simple decimal precision problem

Postby Jope » Sat Sep 10, 2011 5:13 pm

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.
Jope
 
Posts: 2
Joined: Sat Sep 10, 2011 5:08 pm

Re: Simple decimal precision problem

Postby Ramarren » Sun Sep 11, 2011 1:59 am

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.
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: Simple decimal precision problem

Postby nuntius » Sun Sep 11, 2011 7:25 pm

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.
User avatar
nuntius
 
Posts: 500
Joined: Sat Aug 09, 2008 10:44 am
Location: Burlington, MA

Re: Simple decimal precision problem

Postby Jope » Mon Sep 12, 2011 7:30 pm

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
Jope
 
Posts: 2
Joined: Sat Sep 10, 2011 5:08 pm

Re: Simple decimal precision problem

Postby edgar-rft » Mon Sep 12, 2011 11:48 pm

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
Last edited by edgar-rft on Tue Sep 13, 2011 4:11 am, edited 1 time in total.
edgar-rft
 
Posts: 157
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: Simple decimal precision problem

Postby Paul » Tue Sep 13, 2011 1:36 am

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)
Paul
 
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Simple decimal precision problem

Postby edgar-rft » Tue Sep 13, 2011 2:16 am

@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.
edgar-rft
 
Posts: 157
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: Simple decimal precision problem

Postby marcoxa » Thu Sep 22, 2011 1:14 am

You may want to look at the (high quality) OCT library http://common-lisp.net/project/oct/

MA
Marco Antoniotti
marcoxa
 
Posts: 69
Joined: Thu Aug 14, 2008 6:31 pm

Re: Simple decimal precision problem

Postby Konfusius » Thu Sep 22, 2011 11:13 pm

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))
Konfusius
 
Posts: 62
Joined: Fri Jun 10, 2011 6:38 am


Return to Common Lisp

Who is online

Users browsing this forum: No registered users and 1 guest