Yes, I am quite familiar with mathematical questions. But naively I thought that in julia it was done differently and I tried to do something like you suggest.
But I tried with a monster like Vector {Union {Rational, Int}}[ ]
that julia didn’t digest
Fyi, there is this past post from the boss that might still be valid.
You were near!
@show Union{Real,Int}[0, 1//2, 1, 3//2, 4//2]
@show Union{Rational,Int}[0, 1//2, 1, 3//2, 4//2]
yields
Union{Real, Int}[0, 1 // 2, 1, 3 // 2, 4 // 2] = Real[0, 1//2, 1, 3//2, 2//1]
Union{Rational, Int}[0, 1 // 2, 1, 3 // 2, 4 // 2] = Union{Int64, Rational}[0, 1//2, 1, 3//2, 2//1]
That is a very good point from Stefan. But, yet, I kinda expected an AbstractRational
which Integer
inherits, but the concrete Rational
only is defined after Int
is defined. The conventionally identified with this subset, they are not the same as this subset still holds however.
To stay at the problem Y, why ther are two differente types of rational?
julia> Rational{Int}===Rational
false
What is the meaning of the first type (Rational {Int})?
to return to problem X anhoter function to get nice Xticks
siwp(n,d)=if isinteger(n//d) string(Int(n/d)) else string(n,"/",d) end
Instead of converting floats, it is better to use proper integer division: div(n, d)
or n÷d
.
Some reasonably different types of rational
julia> Rational !- Rational{Int}, Rational{Int} != Rational{BigInt}
(true, true)
julia> typeof(Rational(1, 2)), typeof(Rational(big"1", big"2"))
(Rational{Int64}, Rational{BigInt})
julia> sizeof(Rational(1, 2)), sizeof(Rational(Int16(1), Int16(2)))
(16, 4)
julia> typeof(Rational), Rational.body
UnionAll, Rational{T<:Integer}
This is the definition of Rational
:
"""
Rational{T<:Integer} <: Real
Rational number type, with numerator and denominator of type `T`.
Rationals are checked for overflow.
"""
struct Rational{T<:Integer} <: Real
num::T
den::T
# Unexported inner constructor of Rational that bypasses all checks
global unsafe_rational(::Type{T}, num, den) where {T} = new{T}(num, den)
end
So, Rational{Int}
stores the numerator and denominator as Int
, while Rational{BigInt}
(for example) uses BigInt
(and it is therefore an “infinite” precision rational).
I think the whole tread is related to the issue of the default printing of Rationals which is not I think the best possible. I proposed https://github.com/JuliaLang/julia/issues/42626
which was rather well received but no action followed…
out of curiosity I made these tests:
julia> 3//true
3//1
julia> false//5
0//1
julia> typeof(false//5)
Rational{Int64}
The type of the numerator and the denominator needs to be the same. So it gets automatically converted to the largest between the two. You can, however, do:
julia> false // true
false//true
julia> typeof(false // true)
Rational{Bool}
true
and false
are integer (sub)types and when mixed with Int64
get converted to Int64
and:
false//5 == 0//5 == 0//1 # Rational{Int64}
If instead we mix Bool with UInt8
integers we get:
false//UInt8(10) # Rational{UInt8}
Yup. I know.
For this reason I was certain when I tested that the input would be accepted.
what can be done with rationals {boolean} is another matter entirely.