Skip to content
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

changed lcm and gcd implementations for when just one arg is infinite #57067

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Priynsh
Copy link
Contributor

@Priynsh Priynsh commented Jan 16, 2025

Fixes #56991 by adding conditions for both gcd and lcm cases. Also fixes tests for the same i.e. lot of tests regarding gcdx and lcm are removed. Two relevant tests have been added as well.

@inkydragon inkydragon added rationals The Rational type and values thereof maths Mathematical functions labels Jan 16, 2025
@LilithHafner
Copy link
Member

LilithHafner commented Jan 16, 2025

Thanks! Looking at this I'm realizing there is another way to define lcm and gcd that allows lcm(1//1, 1//0), and possibly even lcm(0//1, 1//0) to be well-defined.

Currently, we define

a is a multiple of b if there exists an integer m such that a=mb.

If we change that to

a is a multiple of b if there exists an integer or 1//0, -1//0, or false m such that a=mb.

Then the following are correct:

julia> lcm(1//0, 1//1)
1//0 # currently 1//1

julia> lcm(1//0, 0//1)
0//1 # current behavior, only correct with #57068, otherwise error is appropriate

julia> gcd(1//0, 1//1)
1//1 # currently 1//0

julia> gcd(1//0, 0//1)
1//0 # current behavior, only correct with #57068, otherwise error is appropriate

EDITED to incorporate #57067 (comment)

@LilithHafner LilithHafner added the triage This should be discussed on a triage call label Jan 16, 2025
@Priynsh
Copy link
Contributor Author

Priynsh commented Jan 22, 2025

since the discussion was done, this is the new implementation. Minor change -

a is a multiple of b if there exists an integer or 1//0 or -1//0 or false m such that a=mb.

@LilithHafner
Copy link
Member

Triage wants to add the definition of multiple to gcd to match lcm (but it should be the definition of divides). Triage does not like Lilith's idea of extending integers to include 1//0, -1//0, and false in this case.

@LilithHafner LilithHafner removed the triage This should be discussed on a triage call label Jan 30, 2025
@Priynsh
Copy link
Contributor Author

Priynsh commented Jan 31, 2025

I’ve updated the implementation to throw an error when one of the arguments is infinite in gcd/lcm and fixed the related tests to reflect this change. Additionally, I’ve added a definition for 'multiple' in the docs :)

Copy link
Member

@LilithHafner LilithHafner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I've left some inline comments and this looks good; we should be able to get it merged.

Comment on lines +99 to 103
``a`` is a multiple of ``b`` if there exists an integer ``m`` such
that ``b*m=a``.
``a`` is a multiple of ``b`` if there exists an integer ``m`` such
that ``a=mb``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note is already present; it previously looked like it wasn't because the base commit was out of date.

gcd(x::Rational, y::Rational) = unsafe_rational(gcd(x.num, y.num), lcm(x.den, y.den))
lcm(x::Rational, y::Rational) = unsafe_rational(lcm(x.num, y.num), gcd(x.den, y.den))
function gcd(x::Rational, y::Rational)
if (isinf(x) && !isinf(y)) || (!isinf(x) && isinf(y))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is more clear:

Suggested change
if (isinf(x) && !isinf(y)) || (!isinf(x) && isinf(y))
isinf(x) != isinf(y)

lcm(x::Rational, y::Rational) = unsafe_rational(lcm(x.num, y.num), gcd(x.den, y.den))
function gcd(x::Rational, y::Rational)
if (isinf(x) && !isinf(y)) || (!isinf(x) && isinf(y))
throw(ArgumentError("lcm is not defined"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw(ArgumentError("lcm is not defined"))
throw(ArgumentError("lcm is not defined between infinite and finite numbers"))

if (isinf(x) && !isinf(y)) || (!isinf(x) && isinf(y))
throw(ArgumentError("lcm is not defined"))
end
return unsafe_rational(gcd(x.num, y.num), lcm(x.den, y.den))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return unsafe_rational(gcd(x.num, y.num), lcm(x.den, y.den))
unsafe_rational(gcd(x.num, y.num), lcm(x.den, y.den))

Most of this file uses implicit return stlye

end
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this unrelated whitespace change

Comment on lines +677 to +682

@test_throws ArgumentError gcd(T(1)//T(1), T(1)//T(0))
@test_throws ArgumentError gcd(T(1)//T(0), T(0)//T(1))

@test_throws ArgumentError lcm(T(1)//T(1), T(1)//T(0))
@test_throws ArgumentError lcm(T(1)//T(0), T(1)//T(1))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For tests, let's just change all the existing tests to @test_throws; that way we know we're not losing coverage. It will also make the blame/diff easier to review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maths Mathematical functions rationals The Rational type and values thereof
Projects
None yet
Development

Successfully merging this pull request may close these issues.

lcm should throw when one arg is infinite and the other is finite
3 participants