that’s thrown by constructor, you’re doing arithmetic, where an intermediate step throws error already, I mean, I don’t think they are confusing since they are pretty much saying the same thing: you can’t \div by integer 0
When is it rational (pun intended) to define 1//0 (or even better 2//0)? Should it be disallowed in the constructor (it would be slightly faster, but breaking, not in a major way?). It’s similar to defining Inf (or -Inf), and I’m not sure how often you do that on purpose (for floats, or at least rationals). Julia could have a different way of defining Inf_rat, and also a show methods that shows Inf_rat, not 1//0 or 2//0 etc.
The error message seems by design, but could be amended, and Julia as fast:
@noinline __throw_rational_argerror_zero(T) = throw(ArgumentError("invalid rational: zero($T)//zero($T)"))
function Rational{T}(num::Integer, den::Integer) where T<:Integer
iszero(den) && iszero(num) && __throw_rational_argerror_zero(T)
num, den = divgcd(num, den)
return checked_den(T, T(num), T(den))
end
NaN is more or less like a sentinel value to say “hey it’s undefined” without aborting the program, I personally like to imagine if IEEE floating points were designed in an age where error handling is more systematic, it might have been an error.
Hm, never has. I like when languages do the smartest thing possible, but when using the Ă· operator, I do so accepting that integer arithmetic is more limited.
Let me turn the question around on you. Would you propose that all the following six lines should throw errors?
[Triva] Yes, I thought so, but unlike in IEEE Inf (only two Inf and -Inf, or for each precision), curously rationals actually have infinitly many representations (well finite for Int64-based, infinite for BigInt-based, or limited by memory). This doesn’t pose any problems:
julia> 1//0 == 2//0 # both +Inf up to Inf//0
true
On the other hand while NaN has many representations in IEEE, it has none in rationals, not even analogous to (I guess not done for rationals for performance reasons):
julia> 0/0
NaN
On top of the many NaN representations in IEEE, it’s in addition signed, by default it’s -NaN and showing as NaN always. I guess -NaN was chosen for sorting reasons, +NaN is:
it’s not a number… folks, NaN is an “error,” or “exception”, it’s a value because this is the way to handle runtime exception at low level (you can’t throw and catch error at assembly can you).
why would a “error” have a place in our high-level, language-specific rational number system?
I’m not saying rationals need NaN, I’m very ok with an exception thrown on 0//0. [I would also think it might be ok for 0/0]. To me Inf, and -Inf are also “error conditions”, and seemingly could throw (for rationals, likely would be slower; also for floats). It’s intentional to allow converting Inf and -Inf to rationals, but I at least don’t know it’s very useful? When do you construct Inf intentionally (in floats or rationals)?
Personally, I don’t hate 0//0 having NaN-like properties. I consider NaNs to be useful. They allow you complete a whole block of computations before error checking, rather than requiring you to preemptively handle each operation.
There are (were?) processor modes where NaNs trigger traps, rather than quietly propagate. It’s just that they are virtually unused because NaN propagation works so well and traps are a pain.
Rational provides only a single infinity for each sign, just like IEEE754 floats.
Right, if we chose so, we could have defined it to throw an exception.
I see now one way to generate Infs in rational calculations, i.e. you divide a non-zero by a zero. We need Inf for rationals in one case. It’s not an argument that checking for zero is going to be slower, since there’s already this (slower) check iszero(den) && iszero(num) && __throw_rational_argerror_zero(T) (there’s also Base.checked_den, I might be wrong).
Infs are never generated for other calculations:
julia> 9223372036854775807//1 + 1
ERROR: OverflowError: 9223372036854775807 + 1 overflowed for type Int64
julia> BigInt(9223372036854775807)//1 + 1
9223372036854775808//1
It seems like we could have thrown, not propagate Infs.