diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 23a852cc357..34dd313d442 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -304,48 +304,29 @@ pub trait Real: Signed fn to_radians(&self) -> Self; } -/// Raises a value to the power of exp, using -/// exponentiation by squaring. +/// Raises a value to the power of exp, using exponentiation by squaring. /// /// # Example /// /// ```rust /// use std::num; /// -/// let sixteen = num::pow(2, 4u); -/// assert_eq!(sixteen, 16); +/// assert_eq!(num::pow(2, 4), 16); /// ``` #[inline] -pub fn pow>(num: T, exp: uint) -> T { - let one: uint = One::one(); - let num_one: T = One::one(); - - if exp.is_zero() { return num_one; } - if exp == one { return num.clone(); } - - let mut i: uint = exp; - let mut v: T; - let mut r: T = num_one; - - // This if is to avoid cloning self. - if (i & one) == one { - r = r * num; - i = i - one; - } - - i = i >> one; - v = num * num; - - while !i.is_zero() { - if (i & one) == one { - r = r * v; - i = i - one; +pub fn pow>(mut base: T, mut exp: uint) -> T { + if exp == 1 { base } + else { + let mut acc = one::(); + while exp > 0 { + if (exp & 1) == 1 { + acc = acc * base; + } + base = base * base; + exp = exp >> 1; } - i = i >> one; - v = v * v; + acc } - - r } /// Raise a number to a power. @@ -1670,17 +1651,24 @@ mod tests { #[test] fn test_pow() { - fn assert_pow>(num: T, exp: uint) -> () { - assert_eq!(num::pow(num.clone(), exp), - range(1u, exp).fold(num.clone(), |acc, _| acc * num)); + fn naive_pow>(base: T, exp: uint) -> T { + range(0, exp).fold(one::(), |acc, _| acc * base) } - - assert_eq!(num::pow(3, 0), 1); - assert_eq!(num::pow(5, 1), 5); - assert_pow(-4, 2); - assert_pow(8, 3); - assert_pow(8, 5); - assert_pow(2u64, 50); + macro_rules! assert_pow( + (($num:expr, $exp:expr) => $expected:expr) => {{ + let result = pow($num, $exp); + assert_eq!(result, $expected); + assert_eq!(result, naive_pow($num, $exp)); + }} + ) + assert_pow!((3, 0 ) => 1); + assert_pow!((5, 1 ) => 5); + assert_pow!((-4, 2 ) => 16); + assert_pow!((0.5, 5 ) => 0.03125); + assert_pow!((8, 3 ) => 512); + assert_pow!((8.0, 5 ) => 32768.0); + assert_pow!((8.5, 5 ) => 44370.53125); + assert_pow!((2u64, 50) => 1125899906842624); } }