-
Notifications
You must be signed in to change notification settings - Fork 211
Implement Roots for BigInt and BigUint #56
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
Conversation
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>
There was a problem hiding this 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; |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
| } | ||
|
|
||
| impl Roots for BigUint { | ||
| fn nth_root(&self, n: u32) -> Self { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
benches/bigint.rs
Outdated
| // 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(); |
There was a problem hiding this comment.
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>
|
Thanks for the review! I overrided In addition, after glancing at the test code for implementations of I also fixed some inconsistencies in comments and made panic messages a bit clearer. |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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>
|
Thanks! bors r+ |
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>
Build succeeded |
Supersedes #51 .
Since there is now a
Rootstrait withsqrt,cbrtandnth_rootmethods in thenum-integercrate, this PR implements it forBigIntandBigUinttypes. I also added inherent methods on both types to allow the users access to all these functions without having to importRoots.PS:
nth_rootcurrently usesnum_traits::pow. Should we perhaps wait for #54 to get merged, and then replace the call to use the newpow::Powimplementation onBigUint?