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

Implement Roots for BigInt and BigUint #56

Merged
merged 4 commits into from
Jul 19, 2018
Merged

Conversation

mancabizjak
Copy link
Contributor

@mancabizjak mancabizjak commented Jul 11, 2018

Supersedes #51 .

Since there is now a Roots trait with sqrt, cbrt and nth_root methods in the num-integer crate, this PR implements it for BigInt and BigUint types. I also added inherent methods on both types to allow the users access to all these functions without having to import Roots.

PS: nth_root currently uses num_traits::pow. Should we perhaps wait for #54 to get merged, and then replace the call to use the new pow::Pow implementation on BigUint?

This commit implements num-integer::Roots trait
for BigInt and BigUint types, and also adds sqrt,
cbrt, nth_root as inherent methods to allow access
to them without importing Roots trait. For each
type tests were added as submodules in the roots
test module.

Signed-off-by: Manca Bizjak <manca.bizjak@xlab.si>
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.

Requested a few small changes.

The new Pow ought to be faster, since it can do ops by reference (i.e. less cloning), but we could just make that improvement in a followup.

src/biguint.rs Outdated
}

let n = n as usize;
let n_min_1 = (n as usize) - 1;
Copy link
Member

Choose a reason for hiding this comment

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

Don't need to cast n as usize twice.

src/biguint.rs Outdated

/// Returns the truncated principal square root of `self` --
/// see [Roots::sqrt](Roots::sqrt).
// struct.BigInt.html#trait.Roots
Copy link
Member

Choose a reason for hiding this comment

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

These links don't look right -- did you forget to complete this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Eh, forgot to remove.

src/biguint.rs Outdated
@@ -1026,6 +1026,52 @@ impl Integer for BigUint {
}
}

impl Roots for BigUint {
fn nth_root(&self, n: u32) -> Self {
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 would probably be valuable to have dedicated sqrt and cbrt implementations -- did you try it? Maybe benchmarks would prove me wrong, but we can also wait until later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here are the benchmark results:

test roots_cbrt            ... bench:      48,670 ns/iter (+/- 1,322)
test roots_cbrt_nth_root_3 ... bench:      52,285 ns/iter (+/- 1,541)
test roots_sqrt            ... bench:      53,752 ns/iter (+/- 4,954)
test roots_sqrt_nth_root_2 ... bench:      57,622 ns/iter (+/- 1,585)

roots_cbrt and roots_sqrt test the optimized versions - I took sqrt from #51 and adjusted it for cbrt. The other two benchmarks just called nth_root(2) and nth_root(3) - of course, for the sake of benchmark, I didn't forward the calls to nth_root with n=2 and n=3 to the optimized sqrt and cbrt, but I'll definitely do that, since I see this is how it's done in impls for primitive types as well.

I would prefer to incorporate the dedicated implementations in this PR, although I'm struggling a little since I'm not particularly fond of having parts of nth_root, sqrt, cbrt replicated in all the methods. But I'm not too sure what (if anything) would be best to do about it 🙂

tests/roots.rs Outdated
use std::str::FromStr;

fn check(x: i32, n: u32, expected: i32) {
let big_x: BigUint = FromPrimitive::from_i32(x).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

If you use an unsigned type instead of i32, then From makes this simpler -- BigUint::from(x).

tests/roots.rs Outdated
use num_traits::FromPrimitive;

fn check(x: i32, n: u32, expected: i32) {
let big_x: BigInt = FromPrimitive::from_i32(x).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

Similarly, BigInt::from(x) should be fine.

// hugely impacts the performance of nth_root due to exponentiation to
// the power of n-1. Using very large values for n is also not very realistic,
// and any n > x's bit size produces 1 as a result anyway.
let n: u8 = rng.gen();
Copy link
Member

Choose a reason for hiding this comment

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

This is from a seeded RNG, so what value do you get? I think you might as well just pick a reasonable n directly. Random x is still fine.

This commit overrides default implementations of
Roots::sqrt and Roots::cbrt for BigInt and BigUint
with optimized ones. It also improves tests and
resolves minor inconsistencies.

Signed-off-by: Manca Bizjak <manca.bizjak@xlab.si>
@mancabizjak
Copy link
Contributor Author

Thanks for the review! I overrided sqrt and cbrt methods with versions slightly more performant than their default implementations with nth_root. Recurring checks for trivial cases are now a bit more compact.

In addition, after glancing at the test code for implementations of Roots on PrimInts, I felt that the test code was not thorough enough, so I improved it a little.

I also fixed some inconsistencies in comments and made panic messages a bit clearer.

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.

I understand your concern about duplicating similar code, but I think the performance gain is worth it, and it's not that much code.

src/bigint.rs Outdated

/// Returns the truncated principal square root of `self` --
/// see [Roots::sqrt](Roots::sqrt).
// struct.BigInt.html#trait.Roots
Copy link
Member

Choose a reason for hiding this comment

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

Another stray link? And I think all of these links like [Roots::sqrt](Roots::sqrt) won't actually work, AFAICS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I run cargo doc --no-deps --open and navigate to the page of BigInt or BigUint structs, paths of the form Roots::sqrt are rendered as links to https://docs.rs/num-integer/0.1/num_integer/trait.Roots.html#method.sqrt - I'm a little confused, is this not what we want? I was merely following this RFC, but I could be missing something.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, it seems that works on nightly, but not beta or stable rustc yet. We should make those explicit for now.

src/biguint.rs Outdated
let n_min_1 = n - 1;

let bit_len = self.len() * big_digit::BITS;
let guess = BigUint::one() << (bit_len/n + 1);
Copy link
Member

Choose a reason for hiding this comment

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

The bit_len can be just self.bits(). That should also get a better initial guess when the most-significant word is less "full".

Signed-off-by: Manca Bizjak <manca.bizjak@xlab.si>
Signed-off-by: Manca Bizjak <manca.bizjak@xlab.si>
@cuviper
Copy link
Member

cuviper commented Jul 19, 2018

Thanks!

bors r+

bors bot added a commit that referenced this pull request Jul 19, 2018
56: Implement Roots for BigInt and BigUint r=cuviper a=mancabizjak

Supersedes #51 .

Since there is now a `Roots` trait with `sqrt`, `cbrt` and `nth_root` methods in the `num-integer` crate, this PR implements it for `BigInt` and `BigUint` types. I also added inherent methods on both types to allow the users access to all these functions without having to import `Roots`.

PS: `nth_root` currently  uses `num_traits::pow`. Should we perhaps wait for #54 to get merged, and then replace the call to use the new `pow::Pow` implementation on `BigUint`?

Co-authored-by: Manca Bizjak <manca.bizjak@xlab.si>
@bors
Copy link
Contributor

bors bot commented Jul 19, 2018

Build succeeded

@bors bors bot merged commit 1d45ca9 into rust-num:master Jul 19, 2018
@mancabizjak mancabizjak deleted the impl-roots branch July 30, 2018 11:15
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