Wow quite interesting results. Wonder if its some oddity because I am running this in cygwin. I am using a centrino2 vpro2
I changed the 3 scripts to use $1 instead of a read and the times required are vastly different.
None recursive script I threw together:
$ time ./fibo.sh 10
Fibonacci (10)=55
real 0m0.055s
user 0m0.046s
sys 0m0.030s
Original script from post #2:
$ time ./fibo2.sh 10
0 1 1 2 3 5 8 13 21 34 55
real 0m18.554s
user 0m8.199s
sys 0m4.926s
Script posted by scrutinizer in post #6, well I had to slightly change your while loop cause my shell
could not digest the inline declaration of "i" so mine looks like this at the bottom of the file:
while [ $i -lt $1 ]
do
let i=i+1
Fibonacci $i
done
echo
$ time ./fibo3.sh 10
1 1 2 3 5 8 13 21 34 55
real 0m11.508s
user 0m7.953s
sys 0m4.610s
Yes, the recursive approach is not the most efficient way. What is also interesting is the difference between shells. I changed your code yet again a bit so that it would work in any posix shell:
Fibonacci (){
case $1 in
0|1) printf "$1 " ;;
*) printf "$(( $(Fibonacci $(($1-2))) + $(Fibonacci $(($1-1))) )) ";;
esac
}
i=0
while [ $i -lt $1 ]
do
i=$((i+1))
Fibonacci $i
done
echo
I tested it with bash zsh, dash and ksh:
$ time ./testzsh 10
1 1 2 3 5 8 13 21 34 55
real 0m0.837s
user 0m0.180s
sys 0m0.648s
$ time ./testbash 10
1 1 2 3 5 8 13 21 34 55
real 0m0.887s
user 0m0.300s
sys 0m0.580s
$ time ./testdash 10
1 1 2 3 5 8 13 21 34 55
real 0m0.292s
user 0m0.048s
sys 0m0.240s
$ time ./testksh 10
1 1 2 3 5 8 13 21 34 55
real 0m0.092s
user 0m0.088s
sys 0m0.000s
As is my usual experience, ksh is quite a bit faster then other shells.
I also tested a nonrecursive version (timed in ksh):
$ time ./nonrecurs 10
0 1 1 2 3 5 8 13 21 34 55
real 0m0.013s
user 0m0.016s
sys 0m0.000s
And the difference will become vast once the number goes to 20 and higher.
Computing Fibonacci series via recursion is (because each new element n needs two passes of the algorithm, one for n-1 and one for n-2) not the best idea, to put it mildly. It is easy to show that the Landau-symbol for the runtime characteristics of this algorithm is:
(Basically it means that the time necessary to compute some x will be doubled when x increases by 1.)
The main difference between the original and the improved version was:
x=`expr $x - 1`
and
(( x = x - 1 ))
The reason for this is the fact that "expr" is an external program the shell has to call via the "fork()" system call, which is time intensive. The second variant is completely internal and doesn't need to call an external program so this overhead is removed. The Landau-symbol for the runtime characteristics is still the same as above.
The most efficient implementation is non-recursive and probably something like: