shootout-fannkuch-redux rewrite
Less bound checking and parallelisation. Brute speed improvement is about 15% faster.
This commit is contained in:
parent
d1d8497e53
commit
57d693460b
1 changed files with 47 additions and 76 deletions
|
|
@ -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;
|
||||
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 perm = perm.as_mut_slice();
|
||||
let perm1 = perm1.as_mut_slice();
|
||||
let count = count.as_mut_slice();
|
||||
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 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;
|
||||
}
|
||||
|
||||
let mut flips_count: i32 = 0;
|
||||
let mut k: i32;
|
||||
loop {
|
||||
k = perm[0];
|
||||
if k == 0 {
|
||||
let count_i = count.get_mut(i);
|
||||
if *count_i >= i {
|
||||
*count_i = 0;
|
||||
} else {
|
||||
*count_i += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let k2 = (k+1) >> 1;
|
||||
for i in range(0i32, k2) {
|
||||
perm.swap(i as uint, (k - i) as uint);
|
||||
}
|
||||
tperm.clone_from(&perm);
|
||||
let mut flips_count = 0;
|
||||
loop {
|
||||
let k = *tperm.get(0);
|
||||
if k == 1 { break; }
|
||||
tperm.mut_slice_to(k as uint).reverse();
|
||||
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.
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue