Skip to content

Commit c44a3f6

Browse files
committed
Fix gcdx and lcm with mixed signed/unsigned arguments
1 parent a4e02ca commit c44a3f6

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

base/intfuncs.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ gcd(a::Rational) = checked_abs(a.num) // a.den
148148
lcm(a::Union{Integer,Rational}) = gcd(a)
149149
gcd(a::Unsigned, b::Signed) = gcd(promote(a, abs(b))...)
150150
gcd(a::Signed, b::Unsigned) = gcd(promote(abs(a), b)...)
151+
lcm(a::Unsigned, b::Signed) = lcm(promote(a, abs(b))...)
152+
lcm(a::Signed, b::Unsigned) = lcm(promote(abs(a), b)...)
151153
gcd(a::Real, b::Real) = gcd(promote(a,b)...)
152154
lcm(a::Real, b::Real) = lcm(promote(a,b)...)
153155
gcd(a::Real, b::Real, c::Real...) = gcd(a, gcd(b, c...))
@@ -252,6 +254,16 @@ function gcdx(a::Real, b::Real, cs::Real...)
252254
d′, x, ys... = gcdx(d, cs...)
253255
return d′, i*x, j*x, ys...
254256
end
257+
function gcdx(a::Signed, b::Unsigned)
258+
R = promote_type(typeof(a), typeof(b))
259+
_a = a % signed(R) # handle the case a == typemin(typeof(a)) if R != typeof(a)
260+
d, u, v = gcdx(promote(abs(_a), b)...)
261+
d, flipsign(u, a), v
262+
end
263+
function gcdx(a::Unsigned, b::Signed)
264+
d, v, u = gcdx(b, a)
265+
d, u, v
266+
end
255267

256268
# multiplicative inverse of n mod m, error if none
257269

test/intfuncs.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,35 @@ end
216216
x, y = Int8(-12), UInt(100)
217217
d, u, v = gcdx(x, y)
218218
@test x*u + y*v == d
219+
220+
end
221+
222+
# issue #58025
223+
@testset "Mixed signed/unsigned types" begin
224+
cases = [ # adapted from https://github.com/JuliaLang/julia/pull/59487#issuecomment-3258209203
225+
(UInt16(100), Int8(-101)),
226+
(Int8(-50), UInt16(75)),
227+
(UInt32(12), Int16(-18)),
228+
(Int64(-24), UInt8(36)),
229+
(UInt8(15), Int16(-25)),
230+
(Int32(-42), UInt64(56)),
231+
(UInt128(1000), Int32(-1500)),
232+
(UInt64(0), Int32(-5)),
233+
(Int16(-7), UInt8(0)),
234+
(Int8(-14), UInt8(13)),
235+
]
236+
for (a, b) in cases
237+
g1 = gcd(a, b)
238+
g2, s, t = gcdx(a, b)
239+
@test g1 === g2
240+
@test s*a + t*b == g2
241+
@test g2 >= 0
242+
@test lcm(a, b) === convert(typeof(g1), lcm(widen(a), widen(b)))
243+
end
244+
245+
@test gcdx(Int16(-32768), Int8(-128)) === (Int16(128), Int16(0), Int16(-1))
246+
@test gcdx(Int8(-128), UInt16(256)) === (0x0080, 0xffff, 0x0000)
247+
@test_broken gcd(Int8(-128), UInt16(256)) === 0x0080
219248
end
220249

221250
@testset "gcd/lcm/gcdx for custom types" begin

0 commit comments

Comments
 (0)