# Float -\> Rational numbers?

**URL:** <https://discourse.julialang.org/t/float-rational-numbers/37856>\
**Category:** General Usage\
**Created:** [April 19, 2020, 4:15pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856 "2020-04-19T16:15:18Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 4:15pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/1 "2020-04-19T16:15:18Z")

</div>

I’m curious about the possibility to convert `Float64` numbers to `Rational` numbers for exact computations. I’m a little puzzled by the following:

```julia
julia> x = 2.64
2.64

julia> y = Rational(x)
5944751508129055//2251799813685248

julia> z = 264//100
66//25

julia> Float64(y)
2.64

julia> Float64(z)
2.64

julia> y == z
false

julia> Float64(y) == Float64(z)
true

```

Why does the `Rational` function (constructor?) produce such a horrendously ugly fraction?

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [April 19, 2020, 4:23pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/2 "2020-04-19T16:23:23Z")

</div>

It was discussed recently: [Bug in Julia rational array inplace multiplication](https://discourse.julialang.org/t/bug-in-julia-rational-array-inplace-multiplication/37446)

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 4:24pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/3 "2020-04-19T16:24:24Z")

</div>

Ah. OK.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 4:30pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/4 "2020-04-19T16:30:03Z")

</div>

… I already noticed that Floats such as 2 + 2^{-1} + 2^{-3}, etc. (which can be represented accurately in binary numbers) work as I had hoped…

---

<div class="post-metadata">

**Author:** ![bcmichael](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bcmichael/32/10003_2.png) [@bcmichael](https://discourse.julialang.org/u/bcmichael)\
**Post date:** [April 19, 2020, 4:35pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/5 "2020-04-19T16:35:49Z")

</div>

The rational constructor isn’t doing anything incorrect. There isn’t an exact floating point representation of 2.64. So when you create that float it isn’t exactly 2.64, because it can’t be. When you convert it to a rational it creates a rational of the actual value you have, which again isn’t exactly 2.64. If you want to do exact computations with rationals, you need to create them from exact representations of the numbers you want to use, not inexact floating point representations.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 4:49pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/6 "2020-04-19T16:49:26Z")

</div>

So the following function handles my problem:

```julia
julia> function rationalize(x;sigdigits=16)
       return Int(round(x*10^(sigdigits-1),digits=0))//10^(sigdigits-1)
       end
rationalize (generic function with 1 method)

julia> x = 2.64
2.64

julia> round(x;sigdigits=3)
2.64

julia> round(x;sigdigits=2)
2.6

julia> round(x;sigdigits=1)
3.0

julia> rationalize(x)
66//25

julia> Float64(ans)
2.64

julia> rationalize(x;sigdigits=3)
66//25

julia> rationalize(x;sigdigits=2)
13//5

julia> Float64(ans)
2.6

```

where I have assumed that Float64 numbers have approximately 15 significant digits.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 19, 2020, 5:02pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/7 "2020-04-19T17:02:08Z")

</div>

There’s already a built-in rationalize function:

```julia
julia> rationalize(2.64)
66//25

```

The `Rational` constructor and `convert` do exact conversion, however. If you want to do inexact conversion, you need to explicitly call `rationalize`.

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 5:03pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/8 "2020-04-19T17:03:35Z")

</div>

Ah, so I have reinvented the wheel :-o .

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [April 19, 2020, 5:04pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/9 "2020-04-19T17:04:16Z")

</div>

I’m not sure that using such a function is a good idea, as it suffers from several issues:

**issue #1:** your implementation works only for number of magnitude approximately equal to 1:

```julia
julia> rationalize(1e-20)
0//1

```

This would be relatively easy to fix, taking into account the magnitude of x in the scaling

**issue #2:** this one is more severe IMO: your `rationalize` implementation can give the same rational representation for two different FP numbers:

```julia
julia> x = 0.1
0.1

julia> rationalize(x)
1//10

julia> y = nextfloat(x)
0.10000000000000002

julia> rationalize(y)
1//10

```

I don’t think this is a desired property for something that is designed to work around FP limitations but, depending on your use case, it might be enough. At least, you should be aware of it…

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 19, 2020, 5:05pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/10 "2020-04-19T17:05:57Z")

</div>

The built-in function doesn’t have this issue:

```julia
julia> rationalize(0.1)
1//10

julia> rationalize(nextfloat(0.1))
300239975158034//3002399751580339

```

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 5:06pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/11 "2020-04-19T17:06:49Z")

</div>

…but the built-in function makes 10^{-20} equal to `0//1`.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 19, 2020, 5:07pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/12 "2020-04-19T17:07:49Z")

</div>

Also note the following:

```julia
julia> x = 2.64
2.64

julia> y = Rational(x)
5944751508129055//2251799813685248

julia> z = rationalize(x)
66//25

julia> x == y
true

julia> x == z
false

julia> y == z
false

```

I.e. the `Rational` conversion is exact: `y` is a rational representation of same value as `x` (which is a floating-point approximation of the decimal value 2.64), whereas `z` is not exactly equal to `x` or `y` but is exactly equal to the decimal value 2.64.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 19, 2020, 5:08pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/13 "2020-04-19T17:08:43Z")

</div>

If it’s buggy, file issues!

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [April 19, 2020, 5:15pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/14 "2020-04-19T17:15:13Z")

</div>

> [@BLI](#):
>
> …but the built-in function makes 10−2010^{-20} equal to `0//1` .

Yes, because `rationalize` produces `Rational{Int}` by default, and an `Int` is not large enough to store the denominator in this case.

Everything works if large enough types are used for the numerator and denominator:

```julia
julia> rationalize(1e-20)
0//1

julia> rationalize(BigInt, 1e-20)
1//99999999999999983616

julia> rationalize(BigInt, 1e20)
99999999999999983616//1

```

> [@StefanKarpinski](#):
>
> If it’s buggy, file issues!

I don’t think it is!

---

<div class="post-metadata">

**Author:** ![BLI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bli/32/37206_2.png) [@BLI](https://discourse.julialang.org/u/BLI)\
**Post date:** [April 19, 2020, 5:20pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/15 "2020-04-19T17:20:22Z")

</div>

```julia
julia> rationalize(BigInt,1e-20;tol=1e-36)
1//99999999999999983616

julia> rationalize(BigInt,1e-20;tol=1e-37)
1//100000000000000000000

```

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [April 19, 2020, 8:32pm UTC](https://discourse.julialang.org/t/float-rational-numbers/37856/16 "2020-04-19T20:32:09Z")

</div>

That’s again because `1e-20` is not exactly representable:

```julia
julia> big(1) / big(100000000000000000000)
1.000000000000000000000000000000000000000000000000000000000000000000000000000004e-20

julia> big(1) / big(99999999999999983616)
1.000000000000000163840000000000026843545600000004398046511104000720575940379275e-20

```
