-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improving indexing operations of ranges of bit integers #26608
Comments
Another issue not solved by the above: > (false : true)[3]
ERROR: InexactError()
Stacktrace:
[1] convert(::Type{Bool}, ::Int64) at ./bool.jl:7
[2] getindex(::UnitRange{Bool}, ::Int64) at ./range.jl:476 |
The other thing to keep in mind here is just how performance-sensitive bounds checks are. That really constrains our ability to do fancy things. I'd love for this to be better, though! The abstract |
Thanks for the reply! A few observations:
Considering all this, I think it's best to keep the current implementation, but remove the function new_getindex(v::UnitRange{T}, i::Integer) where T
@_inline_meta
value = v.start + i - 1 # Overflow is well-defined behaviour; if this overflows then value < start regardless
@boundscheck ((i > 0) & (value ≥ v.start) & (value ≤ v.stop)) || throw_boundserror(v, i)
value % T # This improves performance
end It works for all edge cases above. I've benchmarked it with function sum_impl_1(r::UnitRange{T}) where {T}
sum = zero(T)
for idx = linearindices(r) # idx of type Int64
sum += r[idx]
end
sum
end
function sum_impl_2(r::UnitRange{T}) where {T}
sum = zero(T)
for idx = linearindices(r) # idx of type Int64
sum += new_getindex(r, idx)
end
sum
end
function sum_impl_3(r::UnitRange{T}) where {T}
sum = zero(T)
val = r.start
while true
sum += val
val += T(1)
if val == r.stop
break
end
end
sum
end Which gives:
Interpretation: new implementation is faster with bounds checking, and without bounds checking the compiler is able to optimize the whole for-loop out. I'll just make this a PR and see whether it passes tests. |
Currently, computations in
getindex(::UnitRange, ::Integer)
can overflow during the bounds check. If so, it throws an InexactError; not a BoundsError. Compare:I think I have fixed this for all bit integer types (both the range type and index type) with this hack:
But I'm not 100% sure this is the way to go and if I'm covering everything. At least it fixes the problems listed above:
The text was updated successfully, but these errors were encountered: