diff --git a/benches/bigint.rs b/benches/bigint.rs index f2d0fc5d..4e168602 100644 --- a/benches/bigint.rs +++ b/benches/bigint.rs @@ -4,7 +4,7 @@ extern crate test; use num_bigint::{BigInt, BigUint, RandBigInt}; -use num_traits::{FromPrimitive, Num, One, Pow, Zero}; +use num_traits::{FromPrimitive, Num, One, Zero}; use rand::rngs::StdRng; use rand::SeedableRng; use std::mem::replace; @@ -327,16 +327,35 @@ fn hash(b: &mut Bencher) { #[bench] fn pow_bench(b: &mut Bencher) { b.iter(|| { - let upper = 100_usize; - for i in 2..=upper { + let upper = 100_u32; + let mut i_big = BigUint::from(1u32); + for _i in 2..=upper { + i_big += 1u32; for j in 2..=upper { - let i_big = BigUint::from_usize(i).unwrap(); i_big.pow(j); } } }); } +#[bench] +fn pow_bench_bigexp(b: &mut Bencher) { + use num_traits::Pow; + + b.iter(|| { + let upper = 100_u32; + let mut i_big = BigUint::from(1u32); + for _i in 2..=upper { + i_big += 1u32; + let mut j_big = BigUint::from(1u32); + for _j in 2..=upper { + j_big += 1u32; + Pow::pow(&i_big, &j_big); + } + } + }); +} + /// This modulus is the prime from the 2048-bit MODP DH group: /// https://tools.ietf.org/html/rfc3526#section-3 const RFC3526_2048BIT_MODP_GROUP: &str = "\ diff --git a/benches/roots.rs b/benches/roots.rs index 62c32f2d..e6113136 100644 --- a/benches/roots.rs +++ b/benches/roots.rs @@ -4,7 +4,6 @@ extern crate test; use num_bigint::{BigUint, RandBigInt}; -use num_traits::Pow; use rand::rngs::StdRng; use rand::SeedableRng; use test::Bencher; diff --git a/ci/big_quickcheck/src/lib.rs b/ci/big_quickcheck/src/lib.rs index 57451478..e5768ed1 100644 --- a/ci/big_quickcheck/src/lib.rs +++ b/ci/big_quickcheck/src/lib.rs @@ -8,7 +8,7 @@ use num_bigint::{BigInt, BigUint}; use num_integer::Integer; -use num_traits::{Num, One, Pow, Signed, Zero}; +use num_traits::{Num, One, Signed, Zero}; use quickcheck::{QuickCheck, StdThreadGen, TestResult}; use quickcheck_macros::quickcheck; diff --git a/ci/big_rand/src/lib.rs b/ci/big_rand/src/lib.rs index 8bb19116..2c22db0a 100644 --- a/ci/big_rand/src/lib.rs +++ b/ci/big_rand/src/lib.rs @@ -10,7 +10,7 @@ mod torture; mod biguint { use num_bigint::{BigUint, RandBigInt, RandomBits}; - use num_traits::{Pow, Zero}; + use num_traits::Zero; use rand::distributions::Uniform; use rand::thread_rng; use rand::{Rng, SeedableRng}; diff --git a/src/bigint.rs b/src/bigint.rs index 6a405e6a..873983cc 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -937,12 +937,30 @@ fn powsign(sign: Sign, other: &T) -> Sign { macro_rules! pow_impl { ($T:ty) => { + impl Pow<$T> for BigInt { + type Output = BigInt; + + #[inline] + fn pow(self, rhs: $T) -> BigInt { + BigInt::from_biguint(powsign(self.sign, &rhs), self.data.pow(rhs)) + } + } + + impl<'b> Pow<&'b $T> for BigInt { + type Output = BigInt; + + #[inline] + fn pow(self, rhs: &$T) -> BigInt { + BigInt::from_biguint(powsign(self.sign, rhs), self.data.pow(rhs)) + } + } + impl<'a> Pow<$T> for &'a BigInt { type Output = BigInt; #[inline] fn pow(self, rhs: $T) -> BigInt { - BigInt::from_biguint(powsign(self.sign, &rhs), (&self.data).pow(rhs)) + BigInt::from_biguint(powsign(self.sign, &rhs), Pow::pow(&self.data, rhs)) } } @@ -951,7 +969,7 @@ macro_rules! pow_impl { #[inline] fn pow(self, rhs: &$T) -> BigInt { - BigInt::from_biguint(powsign(self.sign, rhs), (&self.data).pow(rhs)) + BigInt::from_biguint(powsign(self.sign, rhs), Pow::pow(&self.data, rhs)) } } }; @@ -3008,6 +3026,11 @@ impl BigInt { Some(self.div(v)) } + /// Returns `self ^ exponent`. + pub fn pow(&self, exponent: u32) -> Self { + Pow::pow(self, exponent) + } + /// Returns `(self ^ exponent) mod modulus` /// /// Note that this rounds like `mod_floor`, not like the `%` operator, diff --git a/src/biguint.rs b/src/biguint.rs index e71e3e94..532448b9 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -547,12 +547,33 @@ impl One for BigUint { impl Unsigned for BigUint {} -impl<'a> Pow for &'a BigUint { +impl<'b> Pow<&'b BigUint> for BigUint { + type Output = BigUint; + + #[inline] + fn pow(self, exp: &BigUint) -> BigUint { + if self.is_one() || exp.is_zero() { + BigUint::one() + } else if self.is_zero() { + BigUint::zero() + } else if let Some(exp) = exp.to_u64() { + self.pow(exp) + } else if let Some(exp) = exp.to_u128() { + self.pow(exp) + } else { + // At this point, `self >= 2` and `exp >= 2¹²⁸`. The smallest possible result given + // `2.pow(2¹²⁸)` would require far more memory than 64-bit targets can address! + panic!("memory overflow") + } + } +} + +impl Pow for BigUint { type Output = BigUint; #[inline] - fn pow(self, exp: BigUint) -> Self::Output { - self.pow(&exp) + fn pow(self, exp: BigUint) -> BigUint { + Pow::pow(self, &exp) } } @@ -560,32 +581,36 @@ impl<'a, 'b> Pow<&'b BigUint> for &'a BigUint { type Output = BigUint; #[inline] - fn pow(self, exp: &BigUint) -> Self::Output { + fn pow(self, exp: &BigUint) -> BigUint { if self.is_one() || exp.is_zero() { BigUint::one() } else if self.is_zero() { BigUint::zero() - } else if let Some(exp) = exp.to_u64() { - self.pow(exp) } else { - // At this point, `self >= 2` and `exp >= 2⁶⁴`. The smallest possible result - // given `2.pow(2⁶⁴)` would take 2.3 exabytes of memory! - panic!("memory overflow") + self.clone().pow(exp) } } } +impl<'a> Pow for &'a BigUint { + type Output = BigUint; + + #[inline] + fn pow(self, exp: BigUint) -> BigUint { + Pow::pow(self, &exp) + } +} + macro_rules! pow_impl { ($T:ty) => { - impl<'a> Pow<$T> for &'a BigUint { + impl Pow<$T> for BigUint { type Output = BigUint; - #[inline] - fn pow(self, mut exp: $T) -> Self::Output { + fn pow(self, mut exp: $T) -> BigUint { if exp == 0 { return BigUint::one(); } - let mut base = self.clone(); + let mut base = self; while exp & 1 == 0 { base = &base * &base; @@ -608,12 +633,33 @@ macro_rules! pow_impl { } } + impl<'b> Pow<&'b $T> for BigUint { + type Output = BigUint; + + #[inline] + fn pow(self, exp: &$T) -> BigUint { + Pow::pow(self, *exp) + } + } + + impl<'a> Pow<$T> for &'a BigUint { + type Output = BigUint; + + #[inline] + fn pow(self, exp: $T) -> BigUint { + if exp == 0 { + return BigUint::one(); + } + Pow::pow(self.clone(), exp) + } + } + impl<'a, 'b> Pow<&'b $T> for &'a BigUint { type Output = BigUint; #[inline] - fn pow(self, exp: &$T) -> Self::Output { - self.pow(*exp) + fn pow(self, exp: &$T) -> BigUint { + Pow::pow(self, *exp) } } }; @@ -2504,6 +2550,11 @@ impl BigUint { self } + /// Returns `self ^ exponent`. + pub fn pow(&self, exponent: u32) -> Self { + Pow::pow(self, exponent) + } + /// Returns `(self ^ exponent) % modulus`. /// /// Panics if the modulus is zero. @@ -2614,7 +2665,7 @@ fn plain_modpow(base: &BigUint, exp_data: &[BigDigit], modulus: &BigUint) -> Big #[test] fn test_plain_modpow() { - let two = BigUint::from(2u32); + let two = &BigUint::from(2u32); let modulus = BigUint::from(0x1100u32); let exp = vec![0, 0b1]; diff --git a/tests/bigint.rs b/tests/bigint.rs index 1a130611..e649dc18 100644 --- a/tests/bigint.rs +++ b/tests/bigint.rs @@ -1148,15 +1148,15 @@ fn test_pow() { let minus_two = BigInt::from(-2i32); macro_rules! check { ($t:ty) => { - assert_eq!(two.pow(0 as $t), one); - assert_eq!(two.pow(1 as $t), two); - assert_eq!(two.pow(2 as $t), four); - assert_eq!(two.pow(3 as $t), eight); - assert_eq!(two.pow(&(3 as $t)), eight); - assert_eq!(minus_two.pow(0 as $t), one, "-2^0"); - assert_eq!(minus_two.pow(1 as $t), minus_two, "-2^1"); - assert_eq!(minus_two.pow(2 as $t), four, "-2^2"); - assert_eq!(minus_two.pow(3 as $t), -&eight, "-2^3"); + assert_eq!(Pow::pow(&two, 0 as $t), one); + assert_eq!(Pow::pow(&two, 1 as $t), two); + assert_eq!(Pow::pow(&two, 2 as $t), four); + assert_eq!(Pow::pow(&two, 3 as $t), eight); + assert_eq!(Pow::pow(&two, &(3 as $t)), eight); + assert_eq!(Pow::pow(&minus_two, 0 as $t), one, "-2^0"); + assert_eq!(Pow::pow(&minus_two, 1 as $t), minus_two, "-2^1"); + assert_eq!(Pow::pow(&minus_two, 2 as $t), four, "-2^2"); + assert_eq!(Pow::pow(&minus_two, 3 as $t), -&eight, "-2^3"); }; } check!(u8); diff --git a/tests/biguint.rs b/tests/biguint.rs index cd944f97..7f99eb4f 100644 --- a/tests/biguint.rs +++ b/tests/biguint.rs @@ -1676,13 +1676,13 @@ fn test_pow() { let twentyfourtyeight = BigUint::from(2048u32); macro_rules! check { ($t:ty) => { - assert_eq!(two.pow(0 as $t), one); - assert_eq!(two.pow(1 as $t), two); - assert_eq!(two.pow(2 as $t), four); - assert_eq!(two.pow(3 as $t), eight); - assert_eq!(two.pow(10 as $t), tentwentyfour); - assert_eq!(two.pow(11 as $t), twentyfourtyeight); - assert_eq!(two.pow(&(11 as $t)), twentyfourtyeight); + assert_eq!(Pow::pow(&two, 0 as $t), one); + assert_eq!(Pow::pow(&two, 1 as $t), two); + assert_eq!(Pow::pow(&two, 2 as $t), four); + assert_eq!(Pow::pow(&two, 3 as $t), eight); + assert_eq!(Pow::pow(&two, 10 as $t), tentwentyfour); + assert_eq!(Pow::pow(&two, 11 as $t), twentyfourtyeight); + assert_eq!(Pow::pow(&two, &(11 as $t)), twentyfourtyeight); }; } check!(u8); diff --git a/tests/roots.rs b/tests/roots.rs index fdd609d2..cfef80c4 100644 --- a/tests/roots.rs +++ b/tests/roots.rs @@ -1,6 +1,6 @@ mod biguint { use num_bigint::BigUint; - use num_traits::{One, Pow, Zero}; + use num_traits::{One, Zero}; use std::{i32, u32}; fn check>(x: T, n: u32) { @@ -114,7 +114,7 @@ mod biguint { mod bigint { use num_bigint::BigInt; - use num_traits::{Pow, Signed}; + use num_traits::Signed; fn check(x: i64, n: u32) { let big_x = BigInt::from(x);