about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-01-20 00:39:05 +1100
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-01-20 18:09:46 +1100
commit509283d149bb81cad728b2c1b81f7ab8ceb206e1 (patch)
tree07b91a333c35549a363458ca5e4643313ca23dde /src/libstd
parentcf56624a4ad7703c8f3fc327b8c385da0a803ea5 (diff)
downloadrust-509283d149bb81cad728b2c1b81f7ab8ceb206e1.tar.gz
rust-509283d149bb81cad728b2c1b81f7ab8ceb206e1.zip
Improve std::num::pow implementation
The implementation has been made more succinct and no longer requires Clone. The coverage of the associated unit test has also been increased to check more combinations of bases, exponents, and expected results.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/num/mod.rs72
1 files changed, 30 insertions, 42 deletions
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<T: Clone+One+Mul<T, T>>(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<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
+    if exp == 1 { base }
+    else {
+        let mut acc = one::<T>();
+        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<T: Eq+Clone+One+Mul<T, T>>(num: T, exp: uint) -> () {
-            assert_eq!(num::pow(num.clone(), exp),
-                       range(1u, exp).fold(num.clone(), |acc, _| acc * num));
+        fn naive_pow<T: One + Mul<T, T>>(base: T, exp: uint) -> T {
+            range(0, exp).fold(one::<T>(), |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);
     }
 }