-
Notifications
You must be signed in to change notification settings - Fork 191
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
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
@@ -1026,6 +1026,52 @@ impl Integer for BigUint { | |||
} | |||
} | |||
|
|||
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
Roots
trait withsqrt
,cbrt
andnth_root
methods in thenum-integer
crate, this PR implements it forBigInt
andBigUint
types. I also added inherent methods on both types to allow the users access to all these functions without having to importRoots
.PS:
nth_root
currently usesnum_traits::pow
. Should we perhaps wait for #54 to get merged, and then replace the call to use the newpow::Pow
implementation onBigUint
?