-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
Julia’s convert function is designed to let users safely convert a floating-point integers such as 2.0 into the equivalent Int value, such as 2. It is documented to throw an error if given a non-integer value:
If
Tis anIntegertype, anInexactErrorwill be raised ifxis not representable byT, for example ifxis not integer-valued, or is outside the range supported byT.
However, it will silently convert infinity into an integer if you give it -Inf16:
julia> isinteger(-Inf16) # infinity is not an integer
false
julia> convert(Int, -Inf16) # but Julia 1.6 – 1.9rc2 will happily turn it into one
-9223372036854775808This behavior only occurs for 16-bit negative infinity:
julia> convert(Int, -Inf32)
ERROR: InexactError: Int64(-Inf)
julia> convert(Int, -Inf64)
ERROR: InexactError: Int64(-Inf)You can convert infinity into an Int32, Int64, or Int128 and it will take on a different integer value for each:
julia> Int32(-Inf16)
-2147483648
julia> Int64(-Inf16)
-9223372036854775808
julia> Int128(-Inf16)
0I debugged this and found that it happens because convert(Int, x) calls Int(x), which has an bug that causes it to mess up the validity check for -Inf16:
function (::Type{$Ti})(x::$Tf)
if ($(Tf(typemin(Ti))) <= x <= $(Tf(typemax(Ti)))) && (round(x, RoundToZero) == x)
return unsafe_trunc($Ti,x)
else
throw(InexactError($(Expr(:quote,Ti.name.name)), $Ti, x))
end
endThe comparison on the second line produces the incorrect behavior, because Float16(typemin(Int)) == -Inf16:
julia> Float16(typemin(Int64))
-Inf16
julia> Float32(typemin(Int64))
-9.223372f18
julia> Float64(typemin(Int64))
-9.223372036854776e18Which causes the interval check to succeed:
Float16(typemin(Int)) <= x < Float16(typemax(Int)))