-
-
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
Fix length(::AbstractUnitRange)
and speed up length(::AbstractUnitRange{<:Rational})
#41479
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 Rational
s, 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 (theInteger
conversion circumvents the correct overflow behavior ofHalfInteger
s).This PR fixes the
length(::AbstractUnitRange)
implementation. Since this change would slow down theAbstractUnitRange{<:Rational}
case, I also added a specialized method forRational
s.Current master:
This PR: