Currently, it seems Inf
is only defined for Float*
. I am wondering if it possible to extend this to other data types, such as Integer
? Then just like zero
and one
, we can have
julia> infinity(1.0)
Inf
julia> infinity(1)
# An `Inf` of type `Int`.
Currently, I mimic the behavior using typemin
and typemax
.
function infinity(::T) where T<:Real
return typemax(T)
end
function isinfinity(n::T) where T<:Real
return n == infinity(n)
end
Edited: I really have to narrow Number
to Real
since the infinity of Complex
is undefined?
Edited 2: After read all suggestions, I come up following solution: just use a Union type. Thanks for all!
struct MyPhysParameter{T<:Real}
value_type::T
allowed_min::Union{T, typeof(Inf)}
allowed_max::Union{T, typeof(Inf)}
end
2 Likes
eh… I think the issue is that there isn’t an infinity defined in Int… the largest value is 2^63-1 with no spares.
I wonder what is the negative version of 0 for?
1 Like
The zero
and one
in my post refer to Base.zero
and Base.one
which simply return 0 and 1 of the same type of the input argument. Examples:
julia> zero(-1.0)
0.0
julia> zero(-1)
0
julia> zero(1 - 2.0im)
0.0 + 0.0im
To Integer
, technically yes, since you can define
struct InfinityInteger <: Integer end
Base.isinfinite(::InfinityInteger) = true
etc, but not to Int
, since that is a bits type that has no representation for infinity.
Practically, since you have to use at least Union
types anyway, I would recommend you just use Inf::Float64
or similar.
2 Likes
Alternatively, you can wrap Int
and use sentinel values.
1 Like
I would go for Union{Int64, InfinityInteger}
. It’s cleaner, and Union{Int64, Float64}
tends to get smushed over time:
julia> [1, Inf]
2-element Array{Float64,1}:
1.0
Inf
julia> identity.(Union{Int, Float64}[1, Inf])
2-element Array{Real,1}:
1
Inf
And there might be cases where it infers better.
InfiniteArrays.jl has Infinity <: Integer
. This is going to be moved to JuliaMath/Infinities.jl as InfiniteCardinal{0}
1 Like
@Tamas_Papp’s answer and others proposing/implementing infinity types are a good ones.
If you want to avoid the Union
…I started working on a NaNIntegers
package, but never finished it. Here’s the start: https://gist.github.com/timholy/569475b24763d1fbd36a42634192cb74. It uses the second-from-top-bit to indicate NaN. You could modify this to use the third-from-top-bit to indicate infinity. Note you have to write your own rules of mathematics, so there’s still a bit of work to do.
I’d generally recommend against mimicking infinity with typemax
:
julia> i = typemax(Int)
9223372036854775807
julia> i+1 == i
false
julia> 2*i == i
false
julia> i-1 == i
false
Any infinity that doesn’t obey those properties is not really infinity.
8 Likes
Great suggestions. However, my usage of infinity is not as ambitious as yours. I only intend to use it as a indicator to mark the infinity, that is to say I will never do any math operations on it.
Here is what I want to do. I want to define a type which describes a physical parameter. Now, with this type I can dispatch some physical computation on it.
struct MyPhysParameter{T<:Real}
description::String
variable_name::String
ascii_label::String
allowed_min::T # the minimum value allowed for this parameter, can be negative infinity
allowed_max::T # the maximum value allowed for this parameter, can be positive infinity
end
So I will need a type stable way to define the infinity.
Typical dispatch case
function compute(::MyPhysParameter, data)
# use the bounds to `rand` or check data validity, etc.
end
If you want to encode the min/max, why not just use typemin
/typemax
?
Edit:
I only intend to use it as a indicator to mark the infinity, that is to say I will never do any math operations on it.
The problem I foresee with calling this Inf
is, what happens when you come back to this after six months away and then forget that you can’t do math operations on it? Calling it Inf
is a slippery slope…
4 Likes