Hacker News new | ask | show | jobs
by Someone 1039 days ago
If you assume/know the decimal you got is the result of rounding some computation, and are more interested in a short description than in the most accurate one.

For example 0.142857 would be 142,857/1,000,000 in your algorithm, but ⅐ in one using best rational approximations (which I assume that paper does, as they’re easy to calculate and, according to a fairly intuitive metric, best)

1 comments

Common Lisp gives you this choice (this being HN, a Lisp mention is obligatory :-)

The CL function #'rational converts a float to a rational assuming the float is completely accurate (i.e. every decimal digit after the last internally-represented one is assumed to be 0), while #'rationalize assumes the float is only accurate to the limit of float precision (i.e. the decimal digits after the last internally-represented one can be anything that would round to the last one).

Both functions preserve the invariant that

  (float (rational x) x) ==  x
and

  (float (rationalize x) x) ==  x
...which is another way of saying they don't lose information.

In practice these tend to be not very useful to me because they don't provide the ability to specify which decimal digit should be considered the last one: They take this parameter from the underlying float representation, which sometimes causes unexpected results (the denominator can end up being larger than you expected) because the input number can effectively have zeros added at the end if the underlying float representation is large enough to capture more bits than you specified when you typed in the number.

In addition, what I really need much of the time is the ability to limit the size of the resulting denominator, like "give me the best rational equivalent of 0.142857 with at most a 3-digit denominator". That function is not built in to Common Lisp but one can write it using the methods in TFA. It loses information of course so a round trip from float->rational->float won't necessarily produce the same result.

> assuming the float is completely accurate (i.e. every decimal digit after the last internally-represented one is assumed to be 0)

Careful though - the float is probably not actually a set of decimal digits but most likely binary ones, so it would be assuming that every binary digit after the last one is zero.

Just because you wrote ‘0.1’ in your source code that doesn’t mean you only have a single significant figure in the float in memory. It’s going to be 0.0001100110011… (repeating 0011 to the extent of your float representation’s precision).

Although the Common Lisp language doesn’t actually appear to require that the internal float radix be 2 - a floating point decimal type would be valid implementation.

> if the underlying float representation is large enough to capture more bits than you specified when you typed in the number.

If you typed in `0.142857` (or however IEEE floats are syntaxed), the correct rational is 142857/1000000. If you want to rationalize relative to number of decimal significant digits, that should be something like `(rationalize "0.142857")` or `(rationalize (radix-mp-float 10 '(1 4 2 8 5 7) -1))`.

> correct rational is 142857/1000000

That would be correct if the underlying representation were decimal. If it's binary, as it is in most Common Lisps,

  (rational 0.142857) --> 9586971/67108864
because the underlying representation is binary, and that denominator is 0x4000000.

My original comment about the representation being large enough to capture more bits than you specified was wrong; the unexpected behavior comes from the internal binary representation and the fact that 9586971/67108864 cannot be reduced.

If you start with integers you get

  (/ 142857 1000000) --> 142857/1000000
so you could write a version of #'rational that gives the expected base-10 result, but you'd first have to convert the float to an integer by multiplying by a power of 10.
> Common Lisp gives you this choice (this being HN, a Lisp mention is obligatory :-)

Yes, we should probably implement a rule. If a post has 100+ comments, it cannot remain on front page unless at least one that mentions Lisp.

dang?

Leave this meta shit on reddit please.

The SNR of this place isn't what it used to be to start with, let's not go out of our way to ADD EVEN MORE noise.

nice language