Parsing large real numbers

Discussion of Common Lisp
Post Reply
vityok
Posts: 20
Joined: Fri Jul 11, 2008 6:20 am
Location: Kyiv, Ukraine
Contact:

Parsing large real numbers

Post by vityok » Tue Jul 22, 2008 11:45 pm

Hello,

What is the proper way to read (parse) real numbers in Common Lisp?

The problem is, that I have to read relatively large real numbers, and both SBCL and CLISP fail:

Code: Select all

[4]> (- (read-from-string "1169991858.90605") 1169991859.32605)
0.0
[5]> (- (read-from-string "1169991858.90605") (read-from-string "1169991859.32605"))
0.0
On SBCL, I have PARSE-NUMBER package installed, but it also fails in a similar way:

Code: Select all

* (- (parse-number:parse-number "1169991858.90605") 1169991859.90605)
0.0
* (parse-number:parse-number "1169991858.90605")
1.1699918e9
The numbers are actually a number of seconds from the Unix Epoch.

Thank you

death
Posts: 17
Joined: Sat Jun 28, 2008 1:44 am

Re: Parsing large real numbers

Post by death » Wed Jul 23, 2008 1:31 am

In this particular case, maybe it would be sufficient to use double-floats:

Code: Select all

(- (let ((*read-default-float-format* 'double-float))
     (read-from-string "1169991858.90605"))
   1169991859.32605d0)
=> -0.4200000762939453d0

makia
Posts: 25
Joined: Tue Jul 22, 2008 2:37 am

Re: Parsing large real numbers

Post by makia » Wed Jul 23, 2008 1:36 am

well, it's tricky field ...
you are using single-floats .... you can use double-floats so you will get:

CL-USER> (- (read-from-string "1169991858.90605") 1169991859.32605)
0.0
CL-USER> *read-default-float-format*
SINGLE-FLOAT
CL-USER> (setf *read-default-float-format* 'double-float)
DOUBLE-FLOAT
CL-USER> (- (read-from-string "1169991858.90605") 1169991859.32605)
-0.4200000762939453

it's part of the IEEE standard because you cant have exact representation in binary
I dont know of any real numbers common lisp library so you can choose precision ....

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Parsing large real numbers

Post by ramarren » Wed Jul 23, 2008 3:07 am

vityok wrote: The numbers are actually a number of seconds from the Unix Epoch.
CLISP also has arbitrary precision floats. Or course, those are slow. But in this particular case, if you may want to parse the seconds and second fraction as integers and either convert them to rational, or handle them separately. This might be overkill though if doubles suffice...

Code: Select all

(defun parse-decimal (string)
  (let ((dot (position #\. string)))
    (+ (parse-integer string :end dot)
       (/ (parse-integer string :start (1+ dot))
          (expt 10 (- (length string) (1+ dot)))))))

(- (parse-decimal "1169991858.90605") (parse-decimal "1169991859.32605")) => -21/50
This will parse a decimal number into a rational. This does not do any error checking or anything, so will fail on malformed input, but I hope you get the idea.

vityok
Posts: 20
Joined: Fri Jul 11, 2008 6:20 am
Location: Kyiv, Ukraine
Contact:

Re: Parsing large real numbers

Post by vityok » Wed Jul 23, 2008 4:28 am

Thank you all for your help.

The approach with modifying default float format does work for me.

Thanks

Post Reply