Page 1 of 1

Parsing large real numbers

Posted: Tue Jul 22, 2008 11:45 pm
by vityok
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

Re: Parsing large real numbers

Posted: Wed Jul 23, 2008 1:31 am
by death
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

Re: Parsing large real numbers

Posted: Wed Jul 23, 2008 1:36 am
by makia
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 ....

Re: Parsing large real numbers

Posted: Wed Jul 23, 2008 3:07 am
by ramarren
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.

Re: Parsing large real numbers

Posted: Wed Jul 23, 2008 4:28 am
by vityok
Thank you all for your help.

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

Thanks