Skip to content

Commit 2e19875

Browse files
Merge #54
54: Implement Pow for BigUint and BigInt r=cuviper a=thomwiggers Implements #29 Co-authored-by: Thom Wiggers <[email protected]>
2 parents c504fa8 + 03e01cb commit 2e19875

File tree

6 files changed

+168
-16
lines changed

6 files changed

+168
-16
lines changed

benches/bigint.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extern crate rand;
1010
use std::mem::replace;
1111
use test::Bencher;
1212
use num_bigint::{BigInt, BigUint, RandBigInt};
13-
use num_traits::{Zero, One, FromPrimitive, Num};
13+
use num_traits::{Zero, One, FromPrimitive, Num, Pow};
1414
use rand::{SeedableRng, StdRng};
1515

1616
fn get_rng() -> StdRng {
@@ -301,7 +301,7 @@ fn pow_bench(b: &mut Bencher) {
301301
for i in 2..upper + 1 {
302302
for j in 2..upper + 1 {
303303
let i_big = BigUint::from_usize(i).unwrap();
304-
num_traits::pow(i_big, j);
304+
i_big.pow(j);
305305
}
306306
}
307307
});

src/bigint.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use serde;
1818

1919
use integer::{Integer, Roots};
2020
use traits::{ToPrimitive, FromPrimitive, Num, CheckedAdd, CheckedSub,
21-
CheckedMul, CheckedDiv, Signed, Zero, One};
21+
CheckedMul, CheckedDiv, Signed, Zero, One, Pow};
2222

2323
use self::Sign::{Minus, NoSign, Plus};
2424

@@ -811,6 +811,54 @@ impl Signed for BigInt {
811811
}
812812
}
813813

814+
815+
/// Help function for pow
816+
///
817+
/// Computes the effect of the exponent on the sign.
818+
#[inline]
819+
fn powsign<T: Integer>(sign: Sign, other: &T) -> Sign {
820+
if other.is_zero() {
821+
Plus
822+
} else if sign != Minus {
823+
sign
824+
} else if other.is_odd() {
825+
sign
826+
} else {
827+
-sign
828+
}
829+
}
830+
831+
macro_rules! pow_impl {
832+
($T:ty) => {
833+
impl<'a> Pow<$T> for &'a BigInt {
834+
type Output = BigInt;
835+
836+
#[inline]
837+
fn pow(self, rhs: $T) -> BigInt {
838+
BigInt::from_biguint(powsign(self.sign, &rhs), (&self.data).pow(rhs))
839+
}
840+
}
841+
842+
impl<'a, 'b> Pow<&'b $T> for &'a BigInt {
843+
type Output = BigInt;
844+
845+
#[inline]
846+
fn pow(self, rhs: &$T) -> BigInt {
847+
BigInt::from_biguint(powsign(self.sign, rhs), (&self.data).pow(rhs))
848+
}
849+
}
850+
}
851+
}
852+
853+
pow_impl!(u8);
854+
pow_impl!(u16);
855+
pow_impl!(u32);
856+
pow_impl!(u64);
857+
pow_impl!(usize);
858+
#[cfg(has_i128)]
859+
pow_impl!(u128);
860+
861+
814862
// A convenience method for getting the absolute value of an i32 in a u32.
815863
#[inline]
816864
fn i32_abs_as_u32(a: i32) -> u32 {

src/biguint.rs

+51-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use serde;
1919

2020
use integer::{Integer, Roots};
2121
use traits::{ToPrimitive, FromPrimitive, Float, Num, Unsigned, CheckedAdd, CheckedSub, CheckedMul,
22-
CheckedDiv, Zero, One, pow};
22+
CheckedDiv, Zero, One, Pow};
2323

2424
use big_digit::{self, BigDigit, DoubleBigDigit};
2525

@@ -434,6 +434,55 @@ impl One for BigUint {
434434

435435
impl Unsigned for BigUint {}
436436

437+
macro_rules! pow_impl {
438+
($T:ty) => {
439+
impl<'a> Pow<$T> for &'a BigUint {
440+
type Output = BigUint;
441+
442+
#[inline]
443+
fn pow(self, mut exp: $T) -> Self::Output {
444+
if exp == 0 { return BigUint::one(); }
445+
let mut base = self.clone();
446+
447+
448+
while exp & 1 == 0 {
449+
base = &base * &base;
450+
exp >>= 1;
451+
}
452+
453+
if exp == 1 { return base; }
454+
455+
let mut acc = base.clone();
456+
while exp > 1 {
457+
exp >>= 1;
458+
base = &base * &base;
459+
if exp & 1 == 1 {
460+
acc = &acc * &base;
461+
}
462+
}
463+
acc
464+
}
465+
}
466+
467+
impl<'a, 'b> Pow<&'b $T> for &'a BigUint {
468+
type Output = BigUint;
469+
470+
#[inline]
471+
fn pow(self, exp: &$T) -> Self::Output {
472+
self.pow(*exp)
473+
}
474+
}
475+
}
476+
}
477+
478+
pow_impl!(u8);
479+
pow_impl!(u16);
480+
pow_impl!(u32);
481+
pow_impl!(u64);
482+
pow_impl!(usize);
483+
#[cfg(has_i128)]
484+
pow_impl!(u128);
485+
437486
forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add);
438487
forward_val_assign!(impl AddAssign for BigUint, add_assign);
439488

@@ -1056,7 +1105,7 @@ impl Roots for BigUint {
10561105

10571106
loop {
10581107
s = u;
1059-
let q = self / pow(s.clone(), n_min_1);
1108+
let q = self / s.pow(n_min_1);
10601109
let t: BigUint = n_min_1 * &s + q;
10611110

10621111
u = t / n;

tests/bigint.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::hash::{BuildHasher, Hasher, Hash};
2020
use std::collections::hash_map::RandomState;
2121

2222
use num_integer::Integer;
23-
use num_traits::{Zero, One, Signed, ToPrimitive, FromPrimitive, Num, Float};
23+
use num_traits::{Zero, One, Signed, ToPrimitive, FromPrimitive, Num, Float, Pow};
2424

2525
mod consts;
2626
use consts::*;
@@ -1092,3 +1092,30 @@ fn test_iter_product_generic() {
10921092
assert_eq!(result, data.iter().product());
10931093
assert_eq!(result, data.into_iter().product());
10941094
}
1095+
1096+
#[test]
1097+
fn test_pow() {
1098+
let one = BigInt::from(1i32);
1099+
let two = BigInt::from(2i32);
1100+
let four = BigInt::from(4i32);
1101+
let eight = BigInt::from(8i32);
1102+
let minus_two = BigInt::from(-2i32);
1103+
macro_rules! check {
1104+
($t:ty) => {
1105+
assert_eq!(two.pow(0 as $t), one);
1106+
assert_eq!(two.pow(1 as $t), two);
1107+
assert_eq!(two.pow(2 as $t), four);
1108+
assert_eq!(two.pow(3 as $t), eight);
1109+
assert_eq!(two.pow(&(3 as $t)), eight);
1110+
assert_eq!(minus_two.pow(0 as $t), one, "-2^0");
1111+
assert_eq!(minus_two.pow(1 as $t), minus_two, "-2^1");
1112+
assert_eq!(minus_two.pow(2 as $t), four, "-2^2");
1113+
assert_eq!(minus_two.pow(3 as $t), -&eight, "-2^3");
1114+
}
1115+
}
1116+
check!(u8);
1117+
check!(u16);
1118+
check!(u32);
1119+
check!(u64);
1120+
check!(usize);
1121+
}

tests/biguint.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::hash::{BuildHasher, Hasher, Hash};
1919
use std::collections::hash_map::RandomState;
2020

2121
use num_traits::{Num, Zero, One, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, ToPrimitive,
22-
FromPrimitive, Float};
22+
FromPrimitive, Float, Pow};
2323

2424
mod consts;
2525
use consts::*;
@@ -766,7 +766,7 @@ fn test_sub() {
766766
#[should_panic]
767767
fn test_sub_fail_on_underflow() {
768768
let (a, b): (BigUint, BigUint) = (Zero::zero(), One::one());
769-
a - b;
769+
let _ = a - b;
770770
}
771771

772772
#[test]
@@ -1530,3 +1530,31 @@ fn test_iter_product_generic() {
15301530
assert_eq!(result, data.iter().product());
15311531
assert_eq!(result, data.into_iter().product());
15321532
}
1533+
1534+
#[test]
1535+
fn test_pow() {
1536+
let one = BigUint::from(1u32);
1537+
let two = BigUint::from(2u32);
1538+
let four = BigUint::from(4u32);
1539+
let eight = BigUint::from(8u32);
1540+
let tentwentyfour = BigUint::from(1024u32);
1541+
let twentyfourtyeight = BigUint::from(2048u32);
1542+
macro_rules! check {
1543+
($t:ty) => {
1544+
assert_eq!(two.pow(0 as $t), one);
1545+
assert_eq!(two.pow(1 as $t), two);
1546+
assert_eq!(two.pow(2 as $t), four);
1547+
assert_eq!(two.pow(3 as $t), eight);
1548+
assert_eq!(two.pow(10 as $t), tentwentyfour);
1549+
assert_eq!(two.pow(11 as $t), twentyfourtyeight);
1550+
assert_eq!(two.pow(&(11 as $t)), twentyfourtyeight);
1551+
}
1552+
}
1553+
check!(u8);
1554+
check!(u16);
1555+
check!(u32);
1556+
check!(u64);
1557+
check!(usize);
1558+
#[cfg(has_i128)]
1559+
check!(u128);
1560+
}

tests/roots.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ extern crate num_traits;
44

55
mod biguint {
66
use num_bigint::BigUint;
7-
use num_traits::pow;
7+
use num_traits::Pow;
88
use std::str::FromStr;
99

1010
fn check(x: u64, n: u32) {
@@ -17,8 +17,8 @@ mod biguint {
1717
assert_eq!(&res, &big_x.cbrt())
1818
}
1919

20-
assert!(pow(res.clone(), n as usize) <= big_x);
21-
assert!(pow(res.clone() + 1u32, n as usize) > big_x);
20+
assert!(res.pow(n) <= big_x);
21+
assert!((res + 1u32).pow(n) > big_x);
2222
}
2323

2424
#[test]
@@ -58,7 +58,7 @@ mod biguint {
5858

5959
mod bigint {
6060
use num_bigint::BigInt;
61-
use num_traits::{Signed, pow};
61+
use num_traits::{Signed, Pow};
6262

6363
fn check(x: i64, n: u32) {
6464
let big_x = BigInt::from(x);
@@ -71,11 +71,11 @@ mod bigint {
7171
}
7272

7373
if big_x.is_negative() {
74-
assert!(pow(res.clone() - 1u32, n as usize) < big_x);
75-
assert!(pow(res.clone(), n as usize) >= big_x);
74+
assert!(res.pow(n) >= big_x);
75+
assert!((res - 1u32).pow(n) < big_x);
7676
} else {
77-
assert!(pow(res.clone(), n as usize) <= big_x);
78-
assert!(pow(res.clone() + 1u32, n as usize) > big_x);
77+
assert!(res.pow(n) <= big_x);
78+
assert!((res + 1u32).pow(n) > big_x);
7979
}
8080
}
8181

0 commit comments

Comments
 (0)