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

Add new function gcd_lcm for calculating the gcd and lcm simultaneously (performance) #12

Closed
wants to merge 1 commit into from

Conversation

haudan
Copy link

@haudan haudan commented Oct 17, 2018

Code relying on Integer::gcd and Integer::lcm for identitcal inputs could be sped up by eliminating unecessary recomputations of the gcd. A function computing and returning both could eliminate implicit gcd calls behind the scenes.

// Current situation
let a = 123.gcd(44); // gcd call #1
let b = 123.lcm(44); // gcd call #2, behind the scenes

// PR
// only 1 gcd call in total, which is reused for the lcm computation
let (a, b) = 123.gcd_lcm(44);

@haudan
Copy link
Author

haudan commented Oct 17, 2018

Checks failed for Rust 1.20 and below, most likely due to the use of the ..= operator. Should I just use .. instead?

Copy link
Member

@cuviper cuviper 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 like this idea, but we'll need a default implementation to avoid a breaking change.

/// assert_eq!(10.gcd_lcm(&4), (2, 20));
/// assert_eq!(8.gcd_lcm(&9), (1, 72));
/// ~~~
fn gcd_lcm(&self, other: &Self) -> (Self, Self);
Copy link
Member

Choose a reason for hiding this comment

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

Note that it's a breaking change to add a trait method without a default implementation. For instance, even num-bigint would fail to build with this until it adds the new method.

I think it should be straightforward to implement this generically, although it probably needs where Self: Clone to do the math by-value. When we do implement this for num-bigint, we can do so without those external clones, so overall this should be fine.

#[test]
fn test_gcd_lcm() {
for i in 1..=255 {
for j in 0..=255 {
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 it will be fine to use a plain range for compatibility.

Maybe I'm missing something, but I'm surprised that this didn't warn about 255 being out of range for i8. But anyway, if you want to be exhaustive, perhaps we should use negative values too with -128..127.

I also notice that you avoid lcm(0, 0), but I think this is actually a bug in our existing implementation. We would get a divide-by-zero since gcd(0, 0) = 0, but Wolfram Alpha says lcm(0, 0) = 0 too.

@cuviper
Copy link
Member

cuviper commented May 20, 2019

#19 also added gcd_lcm - thanks anyway!

@cuviper cuviper closed this May 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants