J'ai le code de travail suivant:
largest_prime=1
for number_under_test in {1..100}
do
is_prime=true
factors=''
for ((divider = 2; divider < number_under_test-1; divider++));
do
remainder=$(($number_under_test % $divider))
[ $remainder == 0 ] && [ is_prime ] && is_prime=false && factors+=$divider' '
done
[ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)" [ $is_prime == true ] && largest_prime=$number_under_test
done
printf "\nLargest Prime= $largest_prime\n"
Ce code court vite est de 0.194 secondes. Cependant, j’ai trouvé le && is_prime= false
lecteur un peu difficile à lire et il pourrait sembler (à l’œil non averti) qu’il était en train d’être testé, plutôt que réglé, ce qui est le cas. Alors j'ai essayé de changer le &&
en un if...then
et cela fonctionne - mais est 75 fois plus lent à 14,48 secondes. C'est surtout visible sur les nombres les plus élevés.
largest_prime=1
for number_under_test in {1..100}
do
is_prime=true
factors=''
for ((divider = 2; divider < number_under_test-1; divider++));
do
remainder=$(($number_under_test % $divider))
if ([ $remainder == 0 ] && [ $is_prime == true ]); then
is_prime=false
factors+=$divider' '
fi
done
[ $is_prime == true ] && echo "${number_under_test} is prime!" || echo "${number_under_test} is NOT prime (factors= $factors)" [ $is_prime == true ] && largest_prime=$number_under_test
done
printf "\nLargest Prime= $largest_prime\n"
Y at-il était d'avoir la clarté du bloc sans la lenteur?
Mise à jour (1/4/2015 10:40 am EST)
Excellent retour J'utilise maintenant ce qui suit. Pas d'autres commentaires ?
largest_prime=1
separator=' '
for number_under_test in {1..100}; {
is_prime=true
factors=''
for ((divider = 2; divider < (number_under_test/2)+1; divider++)) {
remainder=$(($number_under_test % $divider))
if [ $remainder == 0 ]; then
is_prime=false
factors+=$divider' '
fi
}
if $is_prime; then
printf "\n${number_under_test} IS prime\n\n"
largest_prime=$number_under_test
else
printf "${number_under_test} is NOT prime, factors are: "
printf "$factors\n"
fi
}
printf "\nLargest Prime= $largest_prime\n"
shell
shell-script
Michael Durrant
la source
la source
Largest Prime= 100
sur mon ordinateur.number_under_test/2
lieu denumber_under_test-1
: Le facteur n n'est pas supérieur à n / 2, vous pourrez donc toujours trouver tous facteurs pour les nombres non premiers en faisant cela. (De plus, si vous n'étiez intéressé que par le test de primauté, il suffirait d'effectuer une itération jusqu'à sqrt (n), mais Bash n'a de toute façon pas de fonction intégrée permettant de calculer les racines carrées.)(number_under_test/2)+1
pour permettre cela{}
ne sont pas vraiment nécessaires après l'then
article , car lethen
sert déjà comme un opérateur de regroupement (avecelif
,else
oufi
). En fait, dans certains coquillages, vous pourriez écrire, par exemple,for i in 1 2 3; { echo $i; }
sansdo
oudone
.Réponses:
C'est parce que vous créez un sous-shell à chaque fois:
Il suffit d'enlever les parenthèses
Si vous souhaitez grouper des commandes, il existe une syntaxe pour le faire dans le shell actuel :
(le point-virgule final est obligatoire, voir le manuel )
Notez que ce
[ is_prime ]
n'est pas la même chose que[ $is_prime == true ]
: vous pourriez écrire cela simplement$is_prime
(sans crochets) ce qui invoquerait la commandetrue
oufalse
commande intégrée bash .[ is_prime ]
est un test avec un seul argument, la chaîne "is_prime" - lorsqu'un[
seul argument est attribué, le résultat est successif si l'argument n'est pas vide et cette chaîne littérale est toujours non vide, d'où toujours "true".Pour la lisibilité, je changerais la très longue ligne
à
Ne sous-estimez pas les espaces pour améliorer la clarté.
la source
largest_prime=$number_under_test
devrait être dans la branche d'alors (la même erreur est dans l'original)[
invoquent un programme appelé littéralement[
, alors qu'il[[
est implémenté dans le shell - il sera donc plus rapide. Essayez detime for ((i = 0; $i < 1000; i++)); do [ 1 ]; done
comparer à[[
. Voir cette question SO pour plus d'informations.[
, c’est une commande intégrée. À l'invite du shell, tapeztype -a [
ethelp [
which [
revient toujours/usr/bin/[
. Je viens aussi de me rendre compte que je pensais que zsh était identique; pour moi ça me dit que c'est un construit. Mais alors ... pourquoi [[est plus rapide?command -v
est une autre bonnewhich
alternative; voir aussi ici .Je pense que vous travaillez trop dur sur votre fonction. Considérer:
L'arithmétique Shell est assez capable d'évaluer des conditions entières par elle-même. Il a rarement besoin de trop de tests et / ou de missions externes. Cette
while
boucle duplique assez bien vos boucles imbriquées:Bien sûr, ça n'imprime pas beaucoup, je n'ai pas écrit beaucoup, mais, par exemple, le plafond est fixé à 16 plutôt qu'à 101 comme il est écrit ci-dessus et ...
C'est vraiment faire le travail. Et il en faut très peu pour se rapprocher de votre sortie:
Je fais juste ça plutôt que le
echo
et ...Cela fonctionne dans
busybox
. Il est très portable, rapide et facile à utiliser.Votre problème de sous-coquille va se produire dans la plupart des coquilles, mais il est de loin le plus grave dans une
bash
coquille. J'ai alterné entre faire... et la façon dont je l'ai écrit ci-dessus dans plusieurs obus pour un plafond de 101. Je l'
dash
ai fait sans sous-shell en 0,017 seconde et avec le sous-shell en 1,8 seconde.busybox
.149 et 2, zsh. 149 et 4,bash
0,35 et 6, etksh93
en 0,149 et 0,60.ksh93
ne fourche pas pour les sous-coquilles comme les autres coquilles doivent. Alors peut-être que le problème n'est pas tant le sous-shell que le shell .la source
[ "$((...))" -eq "$((...))" ]
fini(( (...) == (...) ))
? Ce dernier est-il moins portable?[ "$((...))" -eq "$((...)) ]
fonctionne dans des shells qui ne prennent pas 15 secondes pour exécuter le programme, et l'autre pas. Si l’avantage de l’un sur l’autre est discutable, cela ne peut que donner un avantage à l’ancien, ce qui signifie qu’il n’ya jamais de bonne raison de l’utiliser(( (...) == (...) ))
.(( ... ))
. Je suis flatté, mais je n'ai pas cette connaissance détaillée. (N'oubliez pas que c'est moi qui viens de demander si le contenu(( ... ))
est moins portable.) Je ne peux donc vraiment pas comprendre votre réponse. : - / Pourriez-vous être un peu plus explicite?"$((...))"
est spécifié par POSIX et l'autre est une extension du shell. Les obus POSIX sont assez capables. Evendash
etposh
gérera correctement les tests de branche comme"$((if_true ? (var=10) : (var=5) ))"
toujours et assignera$var
correctement.busybox
ça casse - ça évalue toujours les deux côtés quelle que soit$if_true
la valeur de.