Mam następujący działający kod:
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"
Ten kod działa szybko i wynosi 0,194 sekundy. Jednak uważam, że && is_prime= false
jest trochę trudny do odczytania i może wyglądać (dla niewprawnego oka), jakby był testowany, a nie ustawiony, co robi. Próbowałem więc zmienić &&
na if...then
i to działa - ale jest 75 razy wolniejsze przy 14,48 sekundy. Jest to najbardziej zauważalne przy wyższych liczbach.
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"
Czy jest jakaś klarowność bloku bez powolności?
Aktualizacja (1/4/2015 10:40 EST)
Świetna opinia! Teraz używam następujących. Jakaś inna opinia ?
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
źródło
źródło
Largest Prime= 100
na moim komputerze.number_under_test/2
zamiast zamiast donumber_under_test-1
: Żaden czynnik liczby n nie jest większy niż n / 2, więc nadal znajdziesz wszystko Czynniki dla liczb niepierwszych wykonując to. (Również jeśli chciałbyś tylko przetestować prymityw, wystarczy iterować do sqrt (n), ale Bash nie ma wbudowanej funkcji do obliczania pierwiastków kwadratowych.)(number_under_test/2)+1
pozwolić{}
nie są naprawdę potrzebne pothen
klauzuli, ponieważthen
już służy jako operator grupującego (wraz zelif
,else
lubfi
). W rzeczywistości w niektórych powłokach można pisać na przykładfor i in 1 2 3; { echo $i; }
bezdo
lubdone
.Odpowiedzi:
Jest tak, ponieważ za każdym razem spawnujesz podpowłokę:
Po prostu usuń nawiasy
Jeśli chcesz pogrupować polecenia, w bieżącej powłoce jest dostępna składnia :
(wymagany jest średnik końcowy, patrz instrukcja )
Zauważ, że
[ is_prime ]
to nie to samo, co[ $is_prime == true ]
: możesz napisać to tak prosto$is_prime
(bez nawiasów), które wywołałoby wbudowane bashtrue
lubfalse
polecenie.[ is_prime ]
jest testem z jednym argumentem, ciągiem „is_prime” - gdy[
podano pojedynczy argument, wynikiem jest sukces, jeśli argument nie jest pusty, a ten literalny ciąg jest zawsze niepusty, a zatem zawsze „prawda”.Dla czytelności zmieniłbym bardzo długą linię
do
Nie lekceważ białych znaków, aby poprawić przejrzystość.
źródło
largest_prime=$number_under_test
powinien być w ówczesnej gałęzi (ten sam błąd jest w oryginale)[
Wywołują program dosłownie wywoływany[
, podczas gdy[[
jest implementowany w powłoce - stąd będzie on szybszy. Spróbujtime for ((i = 0; $i < 1000; i++)); do [ 1 ]; done
i porównaj z[[
. Zobacz to SO pytanie, aby uzyskać więcej informacji.[
, to jest wbudowane. W wierszu poleceń wpisztype -a [
ihelp [
which [
wciąż powraca/usr/bin/[
. Właśnie zdałem sobie sprawę, że sugerowałem, że zsh jest taki sam; dla mnie to mówi mi, że to jest wbudowane. Ale potem ... dlaczego jest [[szybszy?command -v
to kolejna dobrawhich
alternatywa; patrz także tutaj .Myślę, że zbyt ciężko pracujesz nad tą funkcją. Rozważać:
Arytmetyka powłoki jest w stanie sama ocenić warunki całkowite. Rzadko wymaga zbyt wielu testów i / lub zadań zewnętrznych. Ta jedna
while
pętla dość dobrze powiela zagnieżdżone pętle:Nie drukuje się tak dużo, oczywiście, nie napisałem zbyt wiele, ale na przykład ustawiłem pułap na 16 zamiast 101, jak napisano powyżej i ...
To zdecydowanie działa. Przybliżenie wydajności wymaga bardzo niewiele więcej:
Po prostu robienie tego, a nie
echo
...To działa w
busybox
. Jest bardzo przenośny, szybki i łatwy w użyciu.Twój problem z podpowłoką wystąpi w większości powłok, ale jest zdecydowanie najbardziej dotkliwy w
bash
powłoce. Na przemian robiłem... i sposób, w jaki napisałem to powyżej w kilku powłokach dla pułapu 101 i
dash
zrobiłem to bez podpowłoki w 0,017 sekundy i z podpowłoką w 1,8 sekundy.busybox
.149 i 2, zsh .149 i 4,bash
.35 i 6, orazksh93
w .149 i .160.ksh93
nie rozwidla dla podpowłoki, tak jak inne powłoki. Więc może problemem jest nie tyle podpowłoka, ile powłoka .źródło
[ "$((...))" -eq "$((...))" ]
w ciągu(( (...) == (...) ))
? Czy ten ostatni jest mniej przenośny?[ "$((...))" -eq "$((...)) ]
działa w powłokach, których uruchomienie nie zajmuje 15 sekund, a druga nie. Jeśli przewaga jednego nad drugim jest w ogóle wątpliwa, może to dać przewagę tylko temu pierwszemu, co oznacza, że nigdy nie ma dobrego powodu, aby z niego korzystać(( (...) == (...) ))
.(( ... ))
. Pochlebia mi, ale ja nie nie mieć tej szczegółowej wiedzy. (Pamiętaj, to ja właśnie zapytałem, czy(( ... ))
jest mniej przenośny.) Tak więc naprawdę nie mogę zrozumieć twojej odpowiedzi. : - / Czy możesz być bardziej precyzyjny?"$((...))"
jest określony przez POSIX, a drugi to rozszerzenie powłoki. Pociski POSIX są całkiem zdolne. Nawetdash
iposh
poprawnie obsłuży testy gałęzi, takie jak"$((if_true ? (var=10) : (var=5) ))"
i zawsze$var
poprawnie przypisuje .busybox
pęka tam - zawsze ewaluuje obie strony bez względu na$if_true
wartość.