我创建了以下简单的Fibonacci实现: #![feature(test)]extern crate test;pub fn fibonacci_recursive(n: u32) - u32 { match n { 0 = 0, 1 = 1, _ = fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2) }}pub fn fibonacci_imperative(n:
#![feature(test)] extern crate test; pub fn fibonacci_recursive(n: u32) -> u32 { match n { 0 => 0, 1 => 1, _ => fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2) } } pub fn fibonacci_imperative(n: u32) -> u32 { match n { 0 => 0, 1 => 1, _ => { let mut penultimate; let mut last = 1; let mut fib = 0; for _ in 0..n { penultimate = last; last = fib; fib = penultimate + last; } fib } } }
我创建它们试用货架,所以我写了以下基准:
#[cfg(test)] mod tests { use super::*; use test::Bencher; #[bench] fn bench_fibonacci_recursive(b: &mut Bencher) { b.iter(|| { let n = test::black_box(20); fibonacci_recursive(n) }); } #[bench] fn bench_fibonacci_imperative(b: &mut Bencher) { b.iter(|| { let n = test::black_box(20); fibonacci_imperative(n) }); } }
我知道递归实现通常比命令式实现慢,特别是因为Rust不支持尾递归优化(这种实现无论如何都不能使用).但我没想到近2 000次以下差异:
running 2 tests test tests::bench_fibonacci_imperative ... bench: 15 ns/iter (+/- 3) test tests::bench_fibonacci_recursive ... bench: 28,435 ns/iter (+/- 1,114)
我在Windows和Ubuntu上运行了最新的Rust nightly编译器(rustc 1.25.0-nightly)并获得了类似的结果.
这种速度差异是否正常?我写了一些“错误的”吗?或者我的基准有缺陷吗?
正如Shepmaster所说,你应该使用累加器来保持先前计算的fib(n – 1)和fib(n – 2),否则你继续计算相同的值:pub fn fibonacci_recursive(n: u32) -> u32 { fn inner(n: u32, penultimate: u32, last: u32) -> u32 { match n { 0 => penultimate, 1 => last, _ => inner(n - 1, last, penultimate + last), } } inner(n, 0, 1) } fn main() { assert_eq!(fibonacci_recursive(0), 0); assert_eq!(fibonacci_recursive(1), 1); assert_eq!(fibonacci_recursive(2), 1); assert_eq!(fibonacci_recursive(20), 6765); }
最后相当于fib(n – 1).倒数第二个相当于fib(n – 2).