-
-
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
div with rounding modes [+ rounded division] #33040
Conversation
Somehow I missed that we already have |
I feel like @simonbyrne would have the most well-informed opinion on this matter but it seems like a solid idea to me? |
👍 this was my plan from #9283. |
base/div.jl
Outdated
""" | ||
div(x, y, r::RoundingMode=RoundToZero) | ||
|
||
Compute the remainder of `x` after integer division by `y`, with the quotient rounded |
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.
unindent this text
base/div.jl
Outdated
return q + copysign(1, q) | ||
else | ||
@assert rnd == RoundNearestTiesUp | ||
return sign(q) == -1 ? q : q + 1 |
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 don't think it handles negative odd values of y
correctly, e.g. divrem(5, -3, RoundNearestTiesUp)
.
base/div.jl
Outdated
typeof(RoundNearestTiesAway), | ||
typeof(RoundNearestTiesUp)}) | ||
(q, r) = divrem(x, y) | ||
halfy = copysign(y >> 1, r) |
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.
would be good to explain the logic of this function: I don't quite understand it myself.
test/int.jl
Outdated
(3, 2, 2, 2, 2), | ||
(-3, 2, -2, -2, -1), | ||
(5, 2, 2, 3, 3), | ||
(-5, 2, -2, -3, -2)) |
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.
Add some odd divisor cases to the test cases. Also typemin
/typemax
divisors/dividends.
base/div.jl
Outdated
c == -1 && return q | ||
c == 1 && return q + copysign(1, q) | ||
if rnd == RoundNearest | ||
return iseven(q) ? q : q + copysign(1, q) |
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.
None of these handle y == 1
correctly.
c5aa5ee
to
1a374a7
Compare
base/div.jl
Outdated
# The divisior is odd - no ties are possible, just | ||
# round to nearest. N.B. 2r == y is impossible because | ||
# y is odd. | ||
return abs(2r) > abs(y) ? q + copysign(one(q), q) : q |
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 won't work if 2r
overflows, e.g. x,y = typemax(Int)-2,typemax(Int)
@Keno I've added some code that I think should handle overflow correctly. Tests could be improved, and I'm not really sure they will handle mixed Int/UInt arguments correctly. Feel free to adapt as you see fit. |
Oh, I was just gonna use checked_mul, but I like that your version has divrem. We could switch all the divisions to bitshifts, or maybe we just trust that the compiler will figure it out (and that gmp has sufficient special cases). We should also definitely add your overflow test case. |
base/div.jl
Outdated
div(a, b) = div(a, b, RoundToZero) | ||
|
||
""" | ||
rem(x, y, r::RoundingMode) |
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.
maybe rem(x, y, r::RoundingMode=RoundToZero)
as div docstring
ooh, using |
(Just as a note, I meant mul_with_overflow, the checked_ one throws). |
In preparation for supporting other rounding modes in div, create a three-argument div function that takes a rounding mode as the last argument and make this the fundamental fallback for fld/cld.
Rebased and fixed a few more issues. If CI passes, I'd like to start getting this in. |
If we want to check for overflow, we could exhaustively test |
Good idead. Done. This should be good to go from my side. |
I think it's better to give a MethodError here than an approximate answer for non-AbstractFloat reals (e.g. custom integer types).
See JuliaLang/julia#33040 (a3eb9d4). This commit enables the new three-argument div API for BitIntegers.
It looks like in JuliaLang#33040 the `div` docstring was accidentally incorrectly copied from the `rem` docstring, so it currently describes the `rem` operation, not `div`. This commit changes that docstring to correctly describe integer division with custom rounding.
It looks like in #33040 the `div` docstring was accidentally incorrectly copied from the `rem` docstring, so it currently describes the `rem` operation, not `div`. This commit changes that docstring to correctly describe integer division with custom rounding.
I noticed that Line 770 in 09d617a
Should packages still implement a custom override for |
I found myself needing a rounding integer division, i.e. one that does RoundToNearestTiesAway (actually the reference implementation calls for RoundToNearestTiesToward, but the paper doesn't specified and either should be ok). Rather than adding a rntad (round-to-neearest-ties-away-division) function, I figured it may make sense to instead create a generic
div(x, y, r::RoundingMode=RoundToZero)
function, while keepingfld
,cld
(and the two-argument div) as useful shorthands for the rounding modes they represent.This PR just does the re-arranging for the existing code. I haven't yet added the new functionality for round-nearest. Let's discuss whether this direction is sensible.