To complete @Marc Dechico
solution, instead of eval
, passing reference is preferable nowadays (bash >= 4.3) :
factorial_bruno() {
local -i val="$1"
local -n var="$2" # $2 reference
_fact() {
if (( $1 <= 1 )); then
var="$val"
return
fi
((val*=$1-1))
_fact $(($1-1))
}
_fact "$1"
}
declare -i res
factorial_bruno 20 res
printf "res=%d\n" "$res"
If we compare the time on a 1,000 runs of @kojiro
's, @techno
's (catching result for them, as after all we want the result), @Marc Dechici
's, and my solution, we get :
declare -i res
TIMEFORMAT=$'\t%R elapsed, %U user, %S sys'
echo "Kojiro (not catching result) :"
time for i in {1..1000}; do factorial_kojiro $((i%21)); done >/dev/null
echo "Kojiro (catching result) :"
time for i in {1..1000}; do res=$(factorial_kojiro $((i%21))); done
echo "Techno (not catching result) :"
time for i in {1..1000}; do factorial_techno $((i%21)); done >/dev/null
echo "Techno (catching result, 100% data already cached) :"
time for i in {1..1000}; do res=$(factorial_techno $((i%21))); done
_factorials=(1 1)
echo "Techno (catching result, after cache reset) :"
time for i in {1..1000}; do res=$(factorial_techno $((i%21))); done
echo "Marc Dechico :"
time for i in {1..1000}; do factorial_marc $((i%21)) res; done
echo "This solution :"
time for i in {1..1000}; do factorial_bruno $((i%21)) res; done
Kojiro (not catching result) :
0.182 elapsed, 0.182 user, 0.000 sys
Kojiro (catching result) :
1.510 elapsed, 0.973 user, 0.635 sys
Techno (not catching result) :
0.054 elapsed, 0.049 user, 0.004 sys
Techno (catching result, 100% data already cached) :
0.838 elapsed, 0.573 user, 0.330 sys
Techno (catching result, after cache reset) :
2.421 elapsed, 1.658 user, 0.870 sys
Marc Dechico :
0.349 elapsed, 0.348 user, 0.000 sys
This solution :
0.161 elapsed, 0.161 user, 0.000 sys
It is interesting to notice that doing an output (echo/printf
) in a function and catching the result with res=$(func...)
(subshell) is always very expensive, 80% of the time for Kojiro's solution, >95% for Techno one...
EDIT: By adding a cache with similar solution (@techno new solution - the difference is the use of printf -v
instead of using variable reference), we can further improve response time if we need to calculate many times the factorial. With integer limit within bash, that would mean we need to calculate many times the same factorial (probably useful for benchmarks like this one :-)