From fd5346df35cdf3657459973888041813589bb903 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Sat, 2 Nov 2024 15:13:21 -0500 Subject: [PATCH 1/8] Fix and test lcm([1//2, 1//2]) == 1//1 --- base/intfuncs.jl | 3 ++- test/intfuncs.jl | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index e8d4b65305be7..6874a919bc04e 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -150,7 +150,8 @@ gcd(a::T, b::T) where T<:Real = throw(MethodError(gcd, (a,b))) lcm(a::T, b::T) where T<:Real = throw(MethodError(lcm, (a,b))) gcd(abc::AbstractArray{<:Real}) = reduce(gcd, abc; init=zero(eltype(abc))) -lcm(abc::AbstractArray{<:Real}) = reduce(lcm, abc; init=one(eltype(abc))) +lcm(abc::AbstractArray{<:Integer}) = reduce(lcm, abc; init=one(eltype(abc))) +lcm(abc::AbstractArray{<:Real}) = reduce(lcm, abc) # lcm has no identity over the reals. function gcd(abc::AbstractArray{<:Integer}) a = zero(eltype(abc)) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 6f1bde69dddfe..325df5fd4ab24 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -191,6 +191,13 @@ end @test lcm(T[2, 4, 6]) ⟷ T(12) end + + # Issue #55379 + @test lcm([1//2; 1//2]) === lcm([1//2, 1//2]) === lcm(1//2, 1//2) === 1//2 + @test gcd(Int[]) === 0 + @test lcm(Int[]) === 1 + @test gcd(Rational{Int}[]) === 0//1 + @test_throws ArgumentError lcm(Rational{Int}[]) end ⟷(a::Tuple{T, T, T}, b::Tuple{T, T, T}) where T <: Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128} = a === b From 4f06ad09c7f266a43c35c3e10d01d91394e7d9a7 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Mon, 4 Nov 2024 07:28:00 -0600 Subject: [PATCH 2/8] restore `lcm(Rational{Int}[]) === 1//1` --- base/intfuncs.jl | 3 +-- test/intfuncs.jl | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 6874a919bc04e..d230a1da0ea0f 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -150,8 +150,7 @@ gcd(a::T, b::T) where T<:Real = throw(MethodError(gcd, (a,b))) lcm(a::T, b::T) where T<:Real = throw(MethodError(lcm, (a,b))) gcd(abc::AbstractArray{<:Real}) = reduce(gcd, abc; init=zero(eltype(abc))) -lcm(abc::AbstractArray{<:Integer}) = reduce(lcm, abc; init=one(eltype(abc))) -lcm(abc::AbstractArray{<:Real}) = reduce(lcm, abc) # lcm has no identity over the reals. +lcm(abc::AbstractArray{<:Real}) = isempty(abc) ? one(eltype(abc)) : reduce(lcm, abc) # lcm(Rational[]) is not an identity function gcd(abc::AbstractArray{<:Integer}) a = zero(eltype(abc)) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 325df5fd4ab24..ddf105a328da7 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -197,7 +197,7 @@ end @test gcd(Int[]) === 0 @test lcm(Int[]) === 1 @test gcd(Rational{Int}[]) === 0//1 - @test_throws ArgumentError lcm(Rational{Int}[]) + @test lcm(Rational{Int}[]) === 1//1 end ⟷(a::Tuple{T, T, T}, b::Tuple{T, T, T}) where T <: Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128} = a === b From 232402d1bbd65fbe9611621c0881ebfb047b0e98 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Mon, 4 Nov 2024 11:11:57 -0600 Subject: [PATCH 3/8] Fix `lcm([-1])` --- base/intfuncs.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index d230a1da0ea0f..bc5d7b2844641 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -150,7 +150,13 @@ gcd(a::T, b::T) where T<:Real = throw(MethodError(gcd, (a,b))) lcm(a::T, b::T) where T<:Real = throw(MethodError(lcm, (a,b))) gcd(abc::AbstractArray{<:Real}) = reduce(gcd, abc; init=zero(eltype(abc))) -lcm(abc::AbstractArray{<:Real}) = isempty(abc) ? one(eltype(abc)) : reduce(lcm, abc) # lcm(Rational[]) is not an identity +function lcm(abc::AbstractArray{<:Real}) + # Setting init=one(eltype(abc)) is buggy for Rationals. + l = length(abc) + l == 0 && return one(eltype(abc)) + l == 1 && return abs(only(abc)) + return reduce(lcm, abc) +end function gcd(abc::AbstractArray{<:Integer}) a = zero(eltype(abc)) From 79d3f770bcb13ce810d1cb7798713c4e68a30523 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Mon, 4 Nov 2024 11:12:34 -0600 Subject: [PATCH 4/8] Update comment --- base/intfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index bc5d7b2844641..ae7cd016fe245 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -151,7 +151,7 @@ lcm(a::T, b::T) where T<:Real = throw(MethodError(lcm, (a,b))) gcd(abc::AbstractArray{<:Real}) = reduce(gcd, abc; init=zero(eltype(abc))) function lcm(abc::AbstractArray{<:Real}) - # Setting init=one(eltype(abc)) is buggy for Rationals. + # Using reduce with init=one(eltype(abc)) is buggy for Rationals. l = length(abc) l == 0 && return one(eltype(abc)) l == 1 && return abs(only(abc)) From 2ef55d8fbef398a5c34ddcd989b4a2a9c13ae2a6 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Tue, 31 Dec 2024 07:24:31 -0600 Subject: [PATCH 5/8] Make `lcm(Rational[])` throw. --- base/intfuncs.jl | 5 ++++- test/intfuncs.jl | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index ae7cd016fe245..69b7f0386ce01 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -153,7 +153,10 @@ gcd(abc::AbstractArray{<:Real}) = reduce(gcd, abc; init=zero(eltype(abc))) function lcm(abc::AbstractArray{<:Real}) # Using reduce with init=one(eltype(abc)) is buggy for Rationals. l = length(abc) - l == 0 && return one(eltype(abc)) + if l == 0 + eltype(abc) <: Integer && return one(eltype(abc)) + throw(ArgumentError("lcm has no identity over $(eltype(abc))")) + end l == 1 && return abs(only(abc)) return reduce(lcm, abc) end diff --git a/test/intfuncs.jl b/test/intfuncs.jl index ddf105a328da7..5375e1ea55cb3 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -197,7 +197,7 @@ end @test gcd(Int[]) === 0 @test lcm(Int[]) === 1 @test gcd(Rational{Int}[]) === 0//1 - @test lcm(Rational{Int}[]) === 1//1 + @test_throws ArgumentError("lcm has no identity on Rational{Int}") lcm(Rational{Int}[]) end ⟷(a::Tuple{T, T, T}, b::Tuple{T, T, T}) where T <: Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128} = a === b From 42c2f825a38f3f0cd152cced648ca3b2f6d2ed93 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Tue, 31 Dec 2024 09:08:56 -0600 Subject: [PATCH 6/8] Fix tests --- base/intfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 4771e2594373b..13a5007e4c74b 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -155,7 +155,7 @@ function lcm(abc::AbstractArray{<:Real}) l = length(abc) if l == 0 eltype(abc) <: Integer && return one(eltype(abc)) - throw(ArgumentError("lcm has no identity over $(eltype(abc))")) + throw(ArgumentError("lcm has no identity for $(eltype(abc))")) end l == 1 && return abs(only(abc)) return reduce(lcm, abc) From e296436e752c1169d89ecda3e474762f34e8b577 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Tue, 31 Dec 2024 12:49:16 -0600 Subject: [PATCH 7/8] Fix typo --- test/intfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 5375e1ea55cb3..25795bbf8cf6a 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -197,7 +197,7 @@ end @test gcd(Int[]) === 0 @test lcm(Int[]) === 1 @test gcd(Rational{Int}[]) === 0//1 - @test_throws ArgumentError("lcm has no identity on Rational{Int}") lcm(Rational{Int}[]) + @test_throws ArgumentError("lcm has no identity for Rational{Int}") lcm(Rational{Int}[]) end ⟷(a::Tuple{T, T, T}, b::Tuple{T, T, T}) where T <: Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128} = a === b From 9e71fd9ac62110ebd3378d9e6ebe82c8ce6950ba Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Wed, 1 Jan 2025 07:20:55 -0600 Subject: [PATCH 8/8] Interpolate in tests --- test/intfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 25795bbf8cf6a..38f29344d2f30 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -197,7 +197,7 @@ end @test gcd(Int[]) === 0 @test lcm(Int[]) === 1 @test gcd(Rational{Int}[]) === 0//1 - @test_throws ArgumentError("lcm has no identity for Rational{Int}") lcm(Rational{Int}[]) + @test_throws ArgumentError("lcm has no identity for Rational{$Int}") lcm(Rational{Int}[]) end ⟷(a::Tuple{T, T, T}, b::Tuple{T, T, T}) where T <: Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128} = a === b