Fix length(::AbstractUnitRange) and speed up length(::AbstractUnitRange{<:Rational})#41479
Fix length(::AbstractUnitRange) and speed up length(::AbstractUnitRange{<:Rational})#41479KristofferC merged 11 commits intoJuliaLang:masterfrom
length(::AbstractUnitRange) and speed up length(::AbstractUnitRange{<:Rational})#41479Conversation
jw3126
left a comment
There was a problem hiding this comment.
Can you maybe add a mwe test that mimics the failure in HalfIntegers.jl?
Co-authored-by: Jan Weidner <jw3126@gmail.com>
Done! |
Co-authored-by: Jan Weidner <jw3126@gmail.com>
|
Can somebody rerun the failing CI? |
|
I suspect a similar fix is needed for Dividing Line 668 in 56bb340 by oneunit(s) might be sufficient
|
I have now opened a PR for that as well: #41595 |
| # This method is only needed for performance. Since `first(r)` and `last(r)` have the same | ||
| # denominator (because their difference is an integer), `length(r)` can be calulated without | ||
| # calling `gcd`. | ||
| function length(r::AbstractUnitRange{T}) where T<:Rational |
There was a problem hiding this comment.
This method not only adds performance but changes behavior as well: Without this method, length(::AbstractUnitRange{<:Rational}) uses Rational arithmetic, which is checked. The specialized method uses integer arithmetic, so it can overflow.
I realize that we are okay with an overflowing length, but should this also apply to Rationals, which are using checked arithmetic by default? Or should the behavior be changed so that it matches Rational arithmetic?
I will add a specialized checked_length(::AbstractUnitRange{<:Rational}) method in any case.
There was a problem hiding this comment.
I think it is okay, since it should generally only overflow for extreme values that are unlikely
| @_inline_meta | ||
| f = first(r) | ||
| l = last(r) | ||
| return div(l.num - f.num + f.den, f.den) |
There was a problem hiding this comment.
| return div(l.num - f.num + f.den, f.den) | |
| a = fld(l.num, l.den) - fld(f.num, f.den) | |
| return a + oneunit(a) |
This change would reduce the risk of overflow, but would be slightly less performant (two integer divisions instead of one). Is it worth it?
The new
length(::AbstractUnitRange)method from #40382 breaks HalfIntegers.jl (theIntegerconversion circumvents the correct overflow behavior ofHalfIntegers).This PR fixes the
length(::AbstractUnitRange)implementation. Since this change would slow down theAbstractUnitRange{<:Rational}case, I also added a specialized method forRationals.Current master:
This PR: