# Surprise with Rational

**URL:** <https://discourse.julialang.org/t/surprise-with-rational/88694>\
**Category:** New to Julia\
**Tags:** rationals\
**Created:** [October 13, 2022, 9:51pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694 "2022-10-13T21:51:20Z")\
**Posts on this page:** 9\
**Page:** 2

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [October 14, 2022, 3:19pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/21 "2022-10-14T15:19:45Z")

</div>

```julia
julia> (2^62)//(2^62+1) * 2
ERROR: OverflowError: 4611686018427387904 * 2 overflowed for type Int64

julia> float((2^62)//(2^62+1)) * 2
2.0

```

One can overflow the numerator or denominator without even reaching a large number, so overflow-to-infinity is difficult (impossible?) for Rational.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 14, 2022, 3:20pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/22 "2022-10-14T15:20:37Z")

</div>

> [@mikmoore](#):
>
> Personally, I don’t hate `0//0` having `NaN`-like properties.

It doesn’t, but you mean you would have liked it. That likely would slow down all other operations besides division (//), but might have been a good option for debugging. NaN is kept in Posit number system (there named NaR, Not a Real), only one bit-pattern used, but Inf is gone there, so I thought Infs possibly also less useful for rations.

Sorry you’re right, they get converted (I thought they didn’t, that might have been one option to construct them):

```julia
julia> a = -2; a // 0
-1//0

```

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [October 14, 2022, 3:28pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/23 "2022-10-14T15:28:42Z")

</div>

Speed was never something Julia’s `Rational` type offered anyway. Almost every operation requires attempting to reduce the ratio to canonical form. Comparatively, I would anticipate that a check for `0//0` would have a small impact.

For what it’s worth, I never really use `Rational` arithmetic. I don’t have a horse in this race. Down-weight my opinions accordingly.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 14, 2022, 3:36pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/24 "2022-10-14T15:36:50Z")

</div>

> [@mikmoore](#):
>
> Speed was never something Julia’s `Rational` type offered anyway. Almost every operation requires attempting to reduce the ratio to canonical form.

I think Rationals could be much faster actually (also BigInt, in case you want to base them on that; BigInt is basically the default in Python, and not too slow, it’s not the main reason for Python’s slowness). Canonical form is used yes, but seems not needed, and that would be the key to make it faster. Then comparisons get slower, but they are less used.

Raku (formerly known as Perl 6) has rationals as the default number type, so I would look into what they do right (or not), or differently to et speed:

> <https://stackoverflow.com/questions/46840840/does-perl-6-performance-suffer-by-using-rationals-for-decimal-numbers>

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 14, 2022, 7:35pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/25 "2022-10-14T19:35:41Z")

</div>

In practice, both `Inf` and `NaN` are really only ever encountered when dividing by zero (save for the rare occasion when incrementing above 1.7976931\times10^{308}), and taken together they provide computational benefits, allowing you to check for errors only after the chain of computations is done; it’s an incoherent policy to support one and not the other.

Likewise for `1//0` and `0//0`.

Here’s yet another example of how incoherent the current policy is: `1//(1//0)` gives `0//1`, but `1//(im//0)` throws an error.

---

<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:** [October 14, 2022, 7:47pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/26 "2022-10-14T19:47:11Z")

</div>

> [@uniment](#):
>
> By the same spirit, why wouldn’t `0//0` be allowed in order to represent `NaN` with a `Rational`?

A couple of reasons.

One pragmatic reason is that when I originally wrote the Rational code, the `±Inf` cases could mostly use the same logic as for finite rationals if you’re a little clever about it. When I tried to handle `0//0` as well it made everything annoyingly complex and didn’t “fall out” of the normal logic at all. That made us consider whether handling `0//0` was useful in the first place, which brings us to the other reason…

It would be better for most applications if `0/0` raised an immediate error rather than producing `NaN` and letting that poison your computation. The reason it doesn’t work like that was that many of the people debating the IEEE 754 design in the 1980s thought it would have been too slow, so we ended up with a weird compromise where there’s two kinds of NaNs—quiet and signaling—where the latter are supposed to throw errors when produced, but don’t actually because no one ever actually implemented support for it in programming languages, so now all NaNs are effectively quiet. Since Julia’s Rationals are really slow anyway, raising an error is not an issue, so that’s what they do.

In short, handling `0//0` as NaN is annoying and useless. So we don’t.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 14, 2022, 8:03pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/27 "2022-10-14T20:03:46Z")

</div>

Hah, fair enough! I suppose the coherence will come from this:

- Floats support both
- Ints support neither
- Rationals meet halfway

This one feels strange; do you know what’s going on?

`1/(1//0 + 0im)` gives `0//1 + 0//1*im`, but `1//(1//0 + 0im)` throws an error.

🙏

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 14, 2022, 8:29pm UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/28 "2022-10-14T20:29:49Z")

</div>

> [@uniment](#):
>
> taken together they provide computational benefits, allowing you to check for errors only after the chain of computations is done; it’s an incoherent policy to support one and not the other.

Inf doesn’t have any computational benefits for rationals, for a series of calculations, since no calculation will produce such, unless you start with Inf (and why would you want them in your input data?).

I’m totally fine with the “incoherent policy”, since also neither is obviously better, throwing an error or propagating it. I can see it bad NOT stopping right away, imagine spending lots of power, time, on a supercomputer, then seeing `NaN`s (or `Inf` where it applies; for IEEE).

For debugging, I guess running to the end, then checking for them could be helpful (or looking for a needle in a haystack).

The good thing about Julia is that none of the built-in types have much advantage over types in a package (other than being the go-to type), so you can make your own rational type with signaling properties.

`NaN`s in IEEE were meant to be signaling, carrying a payload (`Inf`s do not, only having one bit-pattern, for each, Inf and -Inf), I guess helpful to point to where the error happened IF implemented, but no language (or at least major one) does it by default (or even as opt in, that I know of), so I don’t see it as very helpful to get `NaN`s in the end. But the IEEE float code will be faster not having to check at runtime and have (precise) exceptions.

While I was wrong on 2//0 having a different bit-pattern than 1//0, both meaning Inf, that would be conceivable and the different number being a payload, but then only possible for `Inf`s as opposed to NaNs (and IEEE), which rationals don’t have, nor an easy way to add…

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [October 17, 2022, 12:28am UTC](https://discourse.julialang.org/t/surprise-with-rational/88694/29 "2022-10-17T00:28:31Z")

</div>

> [@uniment](#):
>
> This one feels strange; do you know what’s going on?
> 
> `1/(1//0 + 0im)` gives `0//1 + 0//1*im`, but `1//(1//0 + 0im)` throws an error.

If `z = 1//0 + 0im` then

- `1/z` is computed as `inv(z)`, (see complex.jl:279) which has the code

```julia
function inv(z::Complex)
    c, d = reim(z)
    (isinf(c) | isinf(d)) && return complex(copysign(zero(c), c), flipsign(-zero(d), d))
    complex(c, -d)/(c * c + d * d)
end

```

that is, the second line of the function _handles_ the zero denominator.

- `1//z` is computed, on the other hand, as `conj(z)//abs2(z)` (see rational.jl:79), which is really computing `(1//0)//(1//0)` and hence does integer `0/0` division when trying to reduce a rational to lowest/canonical form.

[Previous page](https://discourse.julialang.org/t/surprise-with-rational/88694.md?page=1)
