Skip to content

Commit 9b474fa

Browse files
oscardssmithKristofferC
authored andcommitted
fix mod for mixes of Signed and Unsigned (#57853)
Previously this was just overfowing producing wrong answers (both for the sign convention and just the wrong modulo class) fixes #57851 (cherry picked from commit 0568917)
1 parent 2a153e8 commit 9b474fa

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

base/int.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,14 @@ function mod(x::T, y::T) where T<:Integer
286286
y == -1 && return T(0) # avoid potential overflow in fld
287287
return x - fld(x, y) * y
288288
end
289-
mod(x::BitSigned, y::Unsigned) = rem(y + unsigned(rem(x, y)), y)
290-
mod(x::Unsigned, y::Signed) = rem(y + signed(rem(x, y)), y)
289+
function mod(x::BitSigned, y::Unsigned)
290+
remval = rem(x, y) # correct iff remval>=0
291+
return unsigned(remval + (remval<zero(remval))*y)
292+
end
293+
function mod(x::Unsigned, y::Signed)
294+
remval = signed(rem(x, y)) #remval>0 so correct iff y>0 or remval==0
295+
return remval + (!iszero(remval) && y<zero(y))*y
296+
end
291297
mod(x::T, y::T) where {T<:Unsigned} = rem(x, y)
292298

293299
# Don't promote integers for div/rem/mod since there is no danger of overflow,

test/int.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,23 @@ end
358358
end
359359
end
360360
end
361+
# exhaustive UInt8/Int8 tests for mixed signedness
362+
for f in (mod, rem)
363+
for i in -128:127
364+
for j in 0:255
365+
if iszero(i)
366+
@test_throws DivideError f(UInt8(j), Int8(i))
367+
else
368+
@test f(UInt8(j), Int8(i)) == f(j, i)
369+
end
370+
if iszero(j)
371+
@test_throws DivideError f(Int8(i), UInt8(j))
372+
else
373+
@test f(Int8(i), UInt8(j)) == f(i,j)
374+
end
375+
end
376+
end
377+
end
361378
end
362379

363380
@testset "Underscores in big_str" begin

0 commit comments

Comments
 (0)