Skip to content

Commit 78f810b

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 aee98f8 commit 78f810b

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

base/int.jl

+8-2
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

+17
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,23 @@ end
362362
end
363363
end
364364
end
365+
# exhaustive UInt8/Int8 tests for mixed signedness
366+
for f in (mod, rem)
367+
for i in -128:127
368+
for j in 0:255
369+
if iszero(i)
370+
@test_throws DivideError f(UInt8(j), Int8(i))
371+
else
372+
@test f(UInt8(j), Int8(i)) == f(j, i)
373+
end
374+
if iszero(j)
375+
@test_throws DivideError f(Int8(i), UInt8(j))
376+
else
377+
@test f(Int8(i), UInt8(j)) == f(i,j)
378+
end
379+
end
380+
end
381+
end
365382
end
366383

367384
@testset "Underscores in big_str" begin

0 commit comments

Comments
 (0)