Skip to content

Commit 57d6934

Browse files
committed
shootout-fannkuch-redux rewrite
Less bound checking and parallelisation. Brute speed improvement is about 15% faster.
1 parent d1d8497 commit 57d6934

File tree

1 file changed

+46
-75
lines changed

1 file changed

+46
-75
lines changed

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

+46-75
Original file line numberDiff line numberDiff line change
@@ -8,94 +8,65 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::os;
11+
use std::cmp::max;
1212

13-
fn max(a: i32, b: i32) -> i32 {
14-
if a > b {
15-
a
16-
} else {
17-
b
18-
}
13+
fn fact(n: uint) -> uint {
14+
range(1, n + 1).fold(1, |accu, i| accu * i)
1915
}
2016

21-
fn fannkuch_redux(n: i32) -> i32 {
22-
let mut perm = Vec::from_elem(n as uint, 0i32);
23-
let mut perm1 = Vec::from_fn(n as uint, |i| i as i32);
24-
let mut count = Vec::from_elem(n as uint, 0i32);
25-
let mut max_flips_count = 0i32;
26-
let mut perm_count = 0i32;
27-
let mut checksum = 0i32;
28-
29-
let perm = perm.as_mut_slice();
30-
let perm1 = perm1.as_mut_slice();
31-
let count = count.as_mut_slice();
32-
33-
let mut r = n;
34-
loop {
35-
while r != 1 {
36-
count[r as uint - 1] = r;
37-
r -= 1;
38-
}
39-
40-
for (perm_i, perm1_i) in perm.mut_iter().zip(perm1.iter()) {
41-
*perm_i = *perm1_i;
42-
}
17+
fn fannkuch(n: uint, i: uint) -> (int, int) {
18+
let mut perm = Vec::from_fn(n, |e| ((n + e - i) % n + 1) as i32);
19+
let mut tperm = perm.clone();
20+
let mut count = Vec::from_elem(n, 0u);
21+
let mut perm_count = 0;
22+
let mut checksum = 0;
4323

44-
let mut flips_count: i32 = 0;
45-
let mut k: i32;
46-
loop {
47-
k = perm[0];
48-
if k == 0 {
49-
break;
24+
for countdown in range(1, fact(n - 1) + 1).rev() {
25+
for i in range(1, n) {
26+
let perm0 = *perm.get(0);
27+
for j in range(0, i) {
28+
*perm.get_mut(j) = *perm.get(j + 1);
5029
}
30+
*perm.get_mut(i) = perm0;
5131

52-
let k2 = (k+1) >> 1;
53-
for i in range(0i32, k2) {
54-
perm.swap(i as uint, (k - i) as uint);
32+
let count_i = count.get_mut(i);
33+
if *count_i >= i {
34+
*count_i = 0;
35+
} else {
36+
*count_i += 1;
37+
break;
5538
}
56-
flips_count += 1;
5739
}
5840

59-
max_flips_count = max(max_flips_count, flips_count);
60-
checksum += if perm_count % 2 == 0 {
61-
flips_count
62-
} else {
63-
-flips_count
64-
};
65-
66-
// Use incremental change to generate another permutation.
41+
tperm.clone_from(&perm);
42+
let mut flips_count = 0;
6743
loop {
68-
if r == n {
69-
println!("{}", checksum);
70-
return max_flips_count;
71-
}
72-
73-
let perm0 = perm1[0];
74-
let mut i: i32 = 0;
75-
while i < r {
76-
let j = i + 1;
77-
perm1[i as uint] = perm1[j as uint];
78-
i = j;
79-
}
80-
perm1[r as uint] = perm0;
81-
82-
count[r as uint] -= 1;
83-
if count[r as uint] > 0 {
84-
break;
85-
}
86-
r += 1;
44+
let k = *tperm.get(0);
45+
if k == 1 { break; }
46+
tperm.mut_slice_to(k as uint).reverse();
47+
flips_count += 1;
8748
}
88-
89-
perm_count += 1;
49+
perm_count = max(perm_count, flips_count);
50+
checksum += if countdown & 1 == 1 {flips_count} else {-flips_count}
9051
}
52+
(checksum, perm_count)
9153
}
9254

9355
fn main() {
94-
let args = os::args();
95-
let n = if args.len() > 1 {
96-
from_str::<i32>(args[1]).unwrap()
97-
} else {
98-
2
99-
};
100-
println!("Pfannkuchen({}) = {}", n as int, fannkuch_redux(n) as int);
56+
let n = std::os::args().get(1).and_then(|arg| from_str(*arg)).unwrap_or(2u);
57+
58+
let (tx, rx) = channel();
59+
for i in range(0, n) {
60+
let tx = tx.clone();
61+
spawn(proc() tx.send(fannkuch(n, i)));
62+
}
63+
drop(tx);
64+
65+
let mut checksum = 0;
66+
let mut perm = 0;
67+
for (cur_cks, cur_perm) in rx.iter() {
68+
checksum += cur_cks;
69+
perm = max(perm, cur_perm);
70+
}
71+
println!("{}\nPfannkuchen({}) = {}", checksum, n, perm);
10172
}

0 commit comments

Comments
 (0)