Browse Source

pow: shift exp powers of 2 before accumulating

We can save a multiplication if we start the accumulation basically at
the first set bit of the exponent, rather than starting at one and
waiting to multiply.  We only need one itself if the exponent is zero,
which is easy to pre-check.

Before:
    test pow_bench         ... bench:   8,267,370 ns/iter (+/- 93,319)

After:
    test pow_bench         ... bench:   7,506,463 ns/iter (+/- 116,311)
Josh Stone 9 years ago
parent
commit
22722ac55d
1 changed files with 14 additions and 13 deletions
  1. 14 13
      src/lib.rs

+ 14 - 13
src/lib.rs

@@ -141,22 +141,23 @@ pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
 /// ```
 /// ```
 #[inline]
 #[inline]
 pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
 pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
-    if exp == 1 { base }
-    else {
-        let mut acc = one::<T>();
-        while exp > 0 {
-            if (exp & 1) == 1 {
-                acc = acc * base.clone();
-            }
+    if exp == 0 { return T::one() }
 
 
-            // avoid overflow if we won't need it
-            if exp > 1 {
-                base = base.clone() * base;
-            }
-            exp = exp >> 1;
+    while exp & 1 == 0 {
+        base = base.clone() * base;
+        exp >>= 1;
+    }
+    if exp == 1 { return base }
+
+    let mut acc = base.clone();
+    while exp > 1 {
+        exp >>= 1;
+        base = base.clone() * base;
+        if exp & 1 == 1 {
+            acc = acc * base.clone();
         }
         }
-        acc
     }
     }
+    acc
 }
 }
 
 
 #[cfg(test)]
 #[cfg(test)]