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.

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

0 votes

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?

```

(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?

`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.

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`

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`

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.

> 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.