Welcome! Please see the About page for a little more info on how this works.

0 votes
in Docs by
retagged by

It says

returns the rational value of num

but the results of (rationalize 1.6) is 8/5 instead of expected 3602879701896397/2251799813685248. What kind of rounding is performed isn't documented.

2 Answers

0 votes
by
selected by
0 votes
by

Why do you expect 3602879701896397/2251799813685248?

by
Because it's the number represented by the literal `1.6` and the documentation doesn't mention rounding. I've checked Common Lisp now:
```
(print (rationalize 1.6d0))
(print (rational 1.6d0))
```
```
8/5
3602879701896397/2251799813685248
```
So `rationalize` does the same, while exact conversion is called `rational`, but how could I have known that before running into this issue if the only conversion function in Clojure is inexact and its behavior is undocumented?
by
`rationalize` works by finding the GCD between the scaled input and 10 power, and representing both numerator and denominator in terms of that, so this will always be a simplified fraction (so here reducing 16/10 based on the gcd 2). But I don't understand how this is inexact or why you expect this result. I don't believe any rounding is occurring, so that's why it's not mentioned.
by
edited by
Rounding is a side effect of converting to decimal because the double precision literal `1.6` represents a number that is a finite fraction in binary, but ~~infinite~~ in decimal [sorry, no, it can't be; investigating now]. So `rationalize` finds a fraction that matches the same number when rounded to double precision, which may be useful in some cases, but it's rather unobvious and I'd only expect it to be implemented in addition to exact conversion, not instead of. Compare to other languages:
Python:
```
from fractions import Fraction
print(Fraction(1.6))
```
`3602879701896397/2251799813685248`
Ruby:
`puts 1.6.to_r`
`3602879701896397/2251799813685248`
Racket:
```
#lang racket
(println (inexact->exact 1.6))
```
`3602879701896397/2251799813685248`
by
BigDecimal.valueOf:
> Translates a double into a BigDecimal, using the double's canonical string representation provided by the Double.toString(double) method.
Double.toString:
> How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.

The implementation of `rationalize` uses `BigDecimal.valueOf`, which does the rounding. Exact conversion would be `new BigDecimal(double)` constructor.
by
Thanks! I've got it now.
...