]> git.lizzy.rs Git - rust.git/commitdiff
shootout-fannkuch-redux rewrite
authorGuillaume Pinot <texitoi@texitoi.eu>
Sat, 19 Apr 2014 23:32:54 +0000 (01:32 +0200)
committerGuillaume Pinot <texitoi@texitoi.eu>
Sun, 20 Apr 2014 01:16:58 +0000 (03:16 +0200)
Less bound checking and parallelisation.  Brute speed improvement
is about 15% faster.

src/test/bench/shootout-fannkuch-redux.rs

index fbea63e65f1264f4be72327b0e87c734e5bf0894..4bea355472de17838940fe727bf6c56614d3fcbe 100644 (file)
@@ -8,94 +8,65 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::os;
+use std::cmp::max;
 
-fn max(a: i32, b: i32) -> i32 {
-    if a > b {
-        a
-    } else {
-        b
-    }
+fn fact(n: uint) -> uint {
+    range(1, n + 1).fold(1, |accu, i| accu * i)
 }
 
-fn fannkuch_redux(n: i32) -> i32 {
-    let mut perm = Vec::from_elem(n as uint, 0i32);
-    let mut perm1 = Vec::from_fn(n as uint, |i| i as i32);
-    let mut count = Vec::from_elem(n as uint, 0i32);
-    let mut max_flips_count = 0i32;
-    let mut perm_count = 0i32;
-    let mut checksum = 0i32;
-
-    let perm = perm.as_mut_slice();
-    let perm1 = perm1.as_mut_slice();
-    let count = count.as_mut_slice();
-
-    let mut r = n;
-    loop {
-        while r != 1 {
-            count[r as uint - 1] = r;
-            r -= 1;
-        }
-
-        for (perm_i, perm1_i) in perm.mut_iter().zip(perm1.iter()) {
-            *perm_i = *perm1_i;
-        }
+fn fannkuch(n: uint, i: uint) -> (int, int) {
+    let mut perm = Vec::from_fn(n, |e| ((n + e - i) % n + 1) as i32);
+    let mut tperm = perm.clone();
+    let mut count = Vec::from_elem(n, 0u);
+    let mut perm_count = 0;
+    let mut checksum = 0;
 
-        let mut flips_count: i32 = 0;
-        let mut k: i32;
-        loop {
-            k = perm[0];
-            if k == 0 {
-                break;
+    for countdown in range(1, fact(n - 1) + 1).rev() {
+        for i in range(1, n) {
+            let perm0 = *perm.get(0);
+            for j in range(0, i) {
+                *perm.get_mut(j) = *perm.get(j + 1);
             }
+            *perm.get_mut(i) = perm0;
 
-            let k2 = (k+1) >> 1;
-            for i in range(0i32, k2) {
-                perm.swap(i as uint, (k - i) as uint);
+            let count_i = count.get_mut(i);
+            if *count_i >= i {
+                *count_i = 0;
+            } else {
+                *count_i += 1;
+                break;
             }
-            flips_count += 1;
         }
 
-        max_flips_count = max(max_flips_count, flips_count);
-        checksum += if perm_count % 2 == 0 {
-            flips_count
-        } else {
-            -flips_count
-        };
-
-        // Use incremental change to generate another permutation.
+        tperm.clone_from(&perm);
+        let mut flips_count = 0;
         loop {
-            if r == n {
-                println!("{}", checksum);
-                return max_flips_count;
-            }
-
-            let perm0 = perm1[0];
-            let mut i: i32 = 0;
-            while i < r {
-                let j = i + 1;
-                perm1[i as uint] = perm1[j as uint];
-                i = j;
-            }
-            perm1[r as uint] = perm0;
-
-            count[r as uint] -= 1;
-            if count[r as uint] > 0 {
-                break;
-            }
-            r += 1;
+            let k = *tperm.get(0);
+            if k == 1 { break; }
+            tperm.mut_slice_to(k as uint).reverse();
+            flips_count += 1;
         }
-
-        perm_count += 1;
+        perm_count = max(perm_count, flips_count);
+        checksum += if countdown & 1 == 1 {flips_count} else {-flips_count}
     }
+    (checksum, perm_count)
 }
 
 fn main() {
-    let args = os::args();
-    let n = if args.len() > 1 {
-        from_str::<i32>(args[1]).unwrap()
-    } else {
-        2
-    };
-    println!("Pfannkuchen({}) = {}", n as int, fannkuch_redux(n) as int);
+    let n = std::os::args().get(1).and_then(|arg| from_str(*arg)).unwrap_or(2u);
+
+    let (tx, rx) = channel();
+    for i in range(0, n) {
+        let tx = tx.clone();
+        spawn(proc() tx.send(fannkuch(n, i)));
+    }
+    drop(tx);
+
+    let mut checksum = 0;
+    let mut perm = 0;
+    for (cur_cks, cur_perm) in rx.iter() {
+        checksum += cur_cks;
+        perm = max(perm, cur_perm);
+    }
+    println!("{}\nPfannkuchen({}) = {}", checksum, n, perm);
 }