Eu tenho o seguinte código de trabalho:
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"
Esse código é executado rapidamente é de 0,194 segundos. No entanto, achei && is_prime= false
um pouco difícil de ler e poderia parecer (para um olho destreinado) como se estivesse sendo testado, em vez de definido como é o que faz. Então, eu tentei mudar o &&
para um if...then
e isso funciona - mas é 75 vezes mais lento em 14,48 segundos. É mais perceptível nos números mais altos.
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"
Existe algum para ter a clareza do bloco sem a lentidão?
Atualização (1/4/2015 10:40 EST)
Ótimo feedback! Agora estou usando o seguinte. Alguma outra resposta ?
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
fonte
fonte
Largest Prime= 100
no meu computador.number_under_test/2
vez de aténumber_under_test-1
: Nenhum fator de um número n é maior que n / 2; portanto, você ainda encontrará tudo fatores para números não primos, fazendo isso. (Além disso, se você estivesse interessado apenas em testar a primidez, seria suficiente iterar até o sqrt (n), mas o Bash não tem uma função(number_under_test/2)+1
para permitir isso{}
não são realmente necessários após athen
cláusula porque othen
já serve como um operador de agrupamento (junto comelif
,else
oufi
). De fato, em algumas conchas, você pode escrever, por exemplo,for i in 1 2 3; { echo $i; }
semdo
oudone
.Respostas:
Isso ocorre porque você gera um sub-shell toda vez:
Basta remover os parênteses
Se você deseja agrupar comandos, há uma sintaxe para fazer isso no shell atual :
(o ponto e vírgula à direita é necessário, consulte o manual )
Observe que
[ is_prime ]
não é o mesmo que[ $is_prime == true ]
: você poderia escrever isso de maneira simples$is_prime
(sem colchetes) que chamaria o comandotrue
ou o built-in do bashfalse
.[ is_prime ]
é um teste com um argumento, a cadeia "is_prime" - quando[
é fornecido um argumento único, o resultado é bem-sucedido se o argumento não estiver vazio e essa cadeia literal for sempre não vazia, portanto sempre "verdadeira".Para facilitar a leitura, eu mudaria a linha muito longa
para
Não subestime o espaço em branco para melhorar a clareza.
fonte
largest_prime=$number_under_test
deve ser no ramo, em seguida, (o mesmo erro está no original)[
está invocando um programa literalmente chamado[
, enquanto[[
implementado no shell - portanto, será mais rápido. Tentetime for ((i = 0; $i < 1000; i++)); do [ 1 ]; done
e compare com[[
. Veja esta questão para mais informações.[
, é um builtin. A partir de um shell prompt, tipotype -a [
ehelp [
which [
ainda retorna/usr/bin/[
. Eu também acabei de perceber que implicava que o zsh era o mesmo; para mim, isso me diz que é um builtin. Mas então ... por que é [[mais rápido?command -v
é outra boawhich
alternativa; veja também aqui .Acho que você está trabalhando demais nessa sua função. Considerar:
A aritmética do shell é bastante capaz de avaliar condições inteiras por si só. Raramente precisa de muitos testes e / ou tarefas externas. Esse
while
loop duplica os loops aninhados bastante bem:Não imprime tanto, é claro, eu não escrevi muito, mas, por exemplo, definindo o teto para 16 em vez de 101, como está escrito acima e ...
Definitivamente, está fazendo o trabalho. E isso requer muito pouco para aproximar sua saída:
Apenas fazendo isso ao invés do
echo
e ...Isso funciona
busybox
. É muito portátil, rápido e fácil de usar.Seu problema de subcamação ocorrerá na maioria das conchas, mas é, de longe , mais agudo em uma
bash
concha. Eu alternei entre fazer... e da maneira que escrevi acima em várias conchas para um teto de 101 e
dash
fiz isso sem o subshell em 0,017 segundos e com o subshell em 1,8 segundos.busybox
.149 e 2, zsh .149 e 4,bash
.35 e 6 eksh93
em .149 e .160.ksh93
não bifurca para subconchas como as outras conchas devem. Então, talvez o problema não seja tanto o subshell, mas também o shell .fonte
[ "$((...))" -eq "$((...))" ]
acabar(( (...) == (...) ))
? O último é menos portátil?[ "$((...))" -eq "$((...)) ]
funciona em conchas que não levam 15 segundos para executar o programa, e o outro não. Se a vantagem de um sobre o outro é questionável, então isso só pode dar vantagem ao primeiro, o que significa que nunca há uma boa razão para usar(( (...) == (...) ))
.(( ... ))
. Estou lisonjeado, mas eu não não tem esse conhecimento detalhado. (Lembre-se, sou eu quem apenas perguntei se(( ... ))
é menos portátil.) Portanto, realmente não consigo entender sua resposta. : - / Você poderia ser um pouco mais explícito?"$((...))"
é especificado e o outro é uma extensão do shell. Os shells POSIX são bastante capazes. Mesmodash
eposh
irá lidar corretamente com testes de ramificação como"$((if_true ? (var=10) : (var=5) ))"
e sempre atribuir$var
corretamente.busybox
quebra lá - sempre avalia ambos os lados, independentemente do$if_true
valor de.