Lisp: coerce float to rational

2007-07-10

Since all floats are mathematical rationals you might expect to be able to coerce a float to a rational. But you can’t:

* (coerce 1d0 'rational)

debugger invoked on a SIMPLE-TYPE-ERROR:
  1.0d0 can't be converted to type RATIONAL.

Here’s a function which does what (coerce x 'rational) might do:

(defun coerce-float-to-rational (x)
  (declare (type float x))
  (let ((b (float-radix x)))
    (multiple-value-bind (signif e s) (integer-decode-float x)
      (* s signif (expt b e))))) 

[Edit on 2007-07-12: jaoswald points out that this functionality is provided by the function rational. So my code could be (part of) an implementation of rational.]

Example:

CL-USER> (coerce-float-to-rational 3.141592653589793)
13176795/4194304                                                                
CL-USER> (coerce-float-to-rational 3.141592653589793d0)
884279719003555/281474976710656                                                 

Numbers that are mathematical integers (which includes all sufficiently large ones) come out as integer objects. Note that for very large numbers you quickly exhaust the precision of the underlying float type:

CL-USER> (coerce-float-to-rational 1e10)
10000000000                                                                     
CL-USER> (coerce-float-to-rational 1e20)
100000002004087734272                                                           
About these ads

2 Responses to “Lisp: coerce float to rational”

  1. jaoswald Says:

    Look in the Hyperspec permuted symbol index under “R” for “Rational.” You can follow the links to the functions RATIONAL and RATIONALIZE.

    (rational 1e20) will give you a precise rational value, (rationalize 1e20) will be more likely to get a “round” value.

    http://www.lisp.org/HyperSpec/Body/fun_rationalcm_rationalize.html

  2. drj11 Says:

    @jaoswald: Thanks for that. I’m a bit of a Lisp novice, so it’s easy for me to not find or simply not know about stuff. I’ve edited the article to add a link.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: