Je veux faire une fonction qui retournera la factorielle d'un nombre en bash
Voici le code actuel qui ne fonctionne pas, quelqu'un peut-il me dire ce qui ne va pas et comment le corriger? Je viens juste de commencer à apprendre Bash et je ne sais pas grand chose.
#!/bash/bin
factorial()
{
let n=$1
if (( "$n" <= "1" ))
then return 1
else
factorial n-1
return $n*$?
fi
return 0
}
factorial 5
echo "factorial 5 = $?"
Il existe plusieurs syntaxes et une logique assez évidente (retourne 0)
Une version de travail est ci-dessous:
#!/bin/bash
factorial()
{
if [[ $1 -le 1 ]]
then
echo 1
else
last=$(factorial $[$1-1])
echo $(($1 * last))
fi
}
factorial 5
Tu es absent:
si la syntaxe est mauvaise
L'appel récursif est mauvais
return is bad (syntaxe eval mauvaise ici)
ligne shbang (est/bin/bash pas/bash/bin)
#!/bin/bash
function factorial()
{
if (( $1 < 2 ))
then
echo 1
else
echo $(( $1 * $(factorial $(( $1 - 1 ))) ))
fi
}
Cela fonctionnera mieux.
(Cela fonctionne de toute façon jusqu'à 25, ce qui devrait suffire à prouver le point concernant la récursion.)
Pour les nombres plus élevés, bc serait l'outil à utiliser, en faisant la neuvième ligne ci-dessus:
echo "$1 * $(factorial $(( $1 - 1 )))" | bc
mais il faut être prudent avec bc -
$ factorial 260
38301958608361692351174979856044918752795567523090969601913008174806\
51475135399533485285838275429773913773383359294010103333339344249624\
06009974551133984962615380298039823284896547262282019684886083204957\
95233137023276627601257325925519566220247124751398891221069403193240\
41688318583612166708334763727216738353107304842707002261430265483385\
20637683911007815690066342722080690052836580858013635214371395680329\
58941156051513954932674117091883540235576934400000000000000000000000\
00000000000000000000000000000000000000000
était assez pénible pour mon pauvre système!
echo
ing peut être le seul moyen d'obtenir un résultat pour n> 5, mais la capture du résultat renvoyé nécessite un sous-shell, ce qui signifie que la récursion coûtera rapidement cher. Une solution moins coûteuse consiste à utiliser une variable:
factorial() {
local -i val=${val:-($1)}
if (( $1 <= 1 )); then
echo $val
return
fi
(( val *= $1 - 1 ))
factorial $(( $1 - 1 ))
}
Si vous voulez vous assurer que val
est non défini au démarrage, utilisez une fonction de wrapping:
factorial() {
local -i val=$1
_fact() {
if (( $1 <= 1 )); then
echo $val
return
fi
(( val *= $1 - 1 ))
_fact $(( $1 - 1 ))
}
_fact $1
}
En comparaison:
# My Method
$ time for i in {0..100}; do factorial $(( RANDOM % 21 )); done > /dev/null
real 0m0.028s
user 0m0.026s
sys 0m0.001s
# A capturing-expression solution
$ time for i in {0..100}; do factorial $(( RANDOM % 21 )); done > /dev/null
real 0m0.652s
user 0m0.221s
sys 0m0.400s
Une autre implémentation utilisant echo
au lieu de return
#!/bin/bash
factorial()
{
if [ $1 -le 1 ]
then
echo 1
else
echo $[ $1 * `factorial $[$1-1]` ]
fi
}
echo "factorial $1 = " `factorial $1`
clear cat
fact()
{
i=$1
if [ $i -eq 0 -o $i -eq 1 ]
then
echo 1
else
f=`expr $i \- 1`
f=$(fact $f)
f=`expr $i \* $f`
echo $f
fi
}
read -p "Enter the number : " n
if [ $n -lt 0 ]
then
echo "ERROR"
else
echo "THE FACTORIAL OF $n : $(fact $n) "
fi