Ich habe den folgenden Arbeitscode:
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"
Dieser Code läuft schnell ist 0,194 Sekunden. Ich fand das jedoch && is_prime= false
ein bisschen schwer zu lesen und es könnte (für das ungeübte Auge) so aussehen, als würde es getestet, anstatt gesetzt zu werden, was es tut. Also habe ich versucht das &&
in ein zu ändern if...then
und das funktioniert - ist aber 75 mal langsamer bei 14,48 Sekunden. Am deutlichsten macht sich dies bei den höheren Zahlen bemerkbar.
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"
Gibt es eine, die die Klarheit des Blocks ohne Langsamkeit haben sollte?
Aktualisierung (04.01.2015, 10:40 Uhr EST)
Tolles Feedback! Ich benutze jetzt die folgenden. Irgendwelche anderen Rückmeldungen ?
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
quelle
quelle
Largest Prime= 100
auf meinem Computer gedruckt .number_under_test/2
statt bis zu iterierennumber_under_test-1
: Kein Faktor einer Zahl n ist größer als n / 2, sodass Sie immer noch alle finden Faktoren für Nicht-Primzahlen auf diese Weise. (Auch wenn Sie nur auf Primheit testen möchten, ist es ausreichend, bis zu sqrt (n) zu iterieren, aber Bash verfügt ohnehin nicht über eine integrierte Funktion zum Berechnen von Quadratwurzeln.)(number_under_test/2)+1
zu ermöglichen{}
sind nicht wirklich nach der benötigtenthen
Klausel , da diethen
bereits als Gruppierungs Operator dienen (zusammen mitelif
,else
oderfi
). Tatsächlich könnte man in einigen Muscheln beispielsweisefor i in 1 2 3; { echo $i; }
ohnedo
oder schreibendone
.Antworten:
Das liegt daran, dass Sie jedes Mal eine Unterschale erzeugen:
Entfernen Sie einfach die Klammern
Wenn Sie Befehle gruppieren möchten, gibt es in der aktuellen Shell die folgende Syntax :
(das abschließende Semikolon ist erforderlich, siehe Handbuch )
Beachten Sie, dass dies
[ is_prime ]
nicht dasselbe ist wie[ $is_prime == true ]
: Sie können dies einfach$is_prime
(ohne eckige Klammern) schreiben, wodurch die integrierte Bashtrue
oder derfalse
Befehl aufgerufen werden .[ is_prime ]
ist ein Test mit einem Argument, der Zeichenfolge "is_prime" - Wenn[
ein einzelnes Argument angegeben wird, ist das Ergebnis erfolgreich, wenn das Argument nicht leer ist und diese Literalzeichenfolge immer nicht leer ist, daher immer "true".Aus Gründen der Lesbarkeit würde ich die sehr lange Zeile ändern
zu
Unterschätzen Sie Leerzeichen nicht, um die Übersichtlichkeit zu verbessern.
quelle
largest_prime=$number_under_test
sollte in der damaligen Branche sein (der gleiche Fehler ist im Original)[
ein Programm aufrufen, das buchstäblich aufgerufen wird[
, während[[
es in der Shell implementiert ist - daher ist es schneller. Versuchen Sietime for ((i = 0; $i < 1000; i++)); do [ 1 ]; done
und vergleichen Sie mit[[
. Siehe diese SO-Frage für weitere Informationen.[
, es ist eine eingebaute. Von einer Shell - Eingabeaufforderung eintype -a [
undhelp [
which [
immer noch zurückkommt/usr/bin/[
. Ich habe auch gerade gemerkt, dass ich angedeutet habe, dass zsh dasselbe ist. für mich bedeutet das, dass es ein eingebautes ist. Aber dann ... warum ist [[schneller?command -v
ist eine weitere gutewhich
Alternative; siehe auch hier .Ich denke, Sie arbeiten viel zu hart an Ihrer Funktion. Erwägen:
Die Shell-Arithmetik ist in der Lage, ganzzahlige Bedingungen selbstständig auszuwerten. Es werden selten zu viele Tests und / oder externe Aufgaben benötigt. Diese eine
while
Schleife dupliziert Ihre verschachtelten Schleifen ziemlich gut:Es wird natürlich nicht so viel gedruckt, ich habe nicht so viel geschrieben, aber zum Beispiel die Obergrenze auf 16 anstatt auf 101 gesetzt, wie oben geschrieben und ...
Es macht definitiv die Arbeit. Und es erfordert sehr wenig anderes, um Ihre Ausgabe zu approximieren:
Tu das einfach lieber als das
echo
und ...Das funktioniert in
busybox
. Es ist sehr portabel, schnell und einfach zu bedienen.Ihr Subshell-Problem tritt in den meisten Shells auf, ist jedoch in einer Shell mit Abstand am akutesten
bash
. Ich wechselte zwischen tun... und so habe ich es oben in mehreren Shells für eine Decke von 101 geschrieben und
dash
es ohne die Subshell in 0,017 Sekunden und mit der Subshell in 1,8 Sekunden gemacht.busybox
.149 und 2, zsh .149 und 4,bash
.35 und 6 undksh93
in .149 und .160.ksh93
Verzweigt sich nicht für Unterschalen, wie die anderen Schalen müssen. Vielleicht liegt das Problem weniger in der Subshell als vielmehr in der Shell .quelle
[ "$((...))" -eq "$((...))" ]
over(( (...) == (...) ))
? Ist letzteres weniger portabel?[ "$((...))" -eq "$((...)) ]
Funktioniert in Shells, die nicht länger als 15 Sekunden benötigen , um das Programm auszuführen, während dies bei der anderen Version nicht der Fall ist. Wenn der Vorteil des einen gegenüber dem anderen überhaupt fraglich ist, kann dies nur dem ersteren den entscheidenden Vorteil verleihen, was bedeutet, dass es nie einen guten Grund gibt, diesen zu nutzen(( (...) == (...) ))
.(( ... ))
. Ich bin geschmeichelt, aber ich habe nicht das detaillierte Wissen. (Denken Sie daran, ich bin derjenige, der gerade gefragt hat, ob er(( ... ))
weniger portabel ist.) Ich kann Ihre Antwort also wirklich nicht verstehen. : - / Könnten Sie etwas expliziter sein?"$((...))"
ist POSIX-spezifiziert und das andere ist eine Shell-Erweiterung. POSIX-Shells sind ziemlich leistungsfähig. Auchdash
undposh
wird richtig Branchentests behandeln"$((if_true ? (var=10) : (var=5) ))"
und immer$var
richtig zuordnen .busybox
bricht dort - es bewertet immer beide Seiten unabhängig vom$if_true
Wert.