Tengo el siguiente código de trabajo:
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"
Este código se ejecuta rápidamente es 0.194 segundos. Sin embargo, me pareció && is_prime= false
un poco difícil de leer y podría parecer (a simple vista) como si estuviera siendo probado en lugar de estar configurado, que es lo que hace. Así que intenté cambiar el &&
a an if...then
y esto funciona, pero es 75 veces más lento a los 14.48 segundos. Es más notable en los números más 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"
¿Hay alguna para tener la claridad del bloque sin la lentitud?
Actualización (1/4/2015 10:40 am EST)
Gran respuesta! Ahora estoy usando lo siguiente. Algún otro comentario ?
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
fuente
fuente
Largest Prime= 100
en mi computadora.number_under_test/2
lugar de hastanumber_under_test-1
: Ningún factor de un número n es mayor que n / 2, por lo que aún encontrará todos factores para números no primos al hacer esto. (Además, si solo estuvieras interesado en probar la primacía, sería suficiente iterar hasta sqrt (n), pero Bash no tiene una función incorporada para calcular raíces cuadradas de todos modos).(number_under_test/2)+1
para permitirlo{}
no son realmente necesarios después de lathen
cláusula porque elthen
ya sirve como operador de agrupación (junto conelif
,else
ofi
). De hecho, en algunos shells, podría escribir, por ejemplo,for i in 1 2 3; { echo $i; }
condo
o sindone
.Respuestas:
Eso es porque estás generando un sub-shell cada vez:
Solo elimina los paréntesis
Si desea agrupar comandos, hay una sintaxis para hacerlo en el shell actual :
(se requiere el punto y coma final, consulte el manual )
Tenga en cuenta que
[ is_prime ]
no es lo mismo que[ $is_prime == true ]
: podría escribir eso simplemente$is_prime
(sin corchetes) que invocaría el bash incorporadotrue
o elfalse
comando.[ is_prime ]
es una prueba con un argumento, la cadena "is_prime": cuando[
se le da un único argumento, el resultado es exitoso si el argumento no está vacío, y esa cadena literal siempre no está vacía, por lo tanto, siempre es "verdadera".Para facilitar la lectura, cambiaría la línea muy larga
a
No subestimes los espacios en blanco para mejorar la claridad.
fuente
largest_prime=$number_under_test
error[
está invocando un programa llamado literalmente[
, mientras que[[
se implementa en el shell, por lo tanto, será más rápido. Intentatime for ((i = 0; $i < 1000; i++)); do [ 1 ]; done
y compara con[[
. Vea esta pregunta SO para más información.[
, es un incorporado. Desde un indicador de comandos de shell, escribatype -a [
yhelp [
which [
todavía regresa/usr/bin/[
. También me di cuenta de que implicaba que zsh era igual; para mí eso me dice que es una construcción. Pero entonces ... ¿por qué es [[más rápido?command -v
es otra buenawhich
alternativa; ver también aquí .Creo que estás trabajando demasiado duro en esa función tuya. Considerar:
La aritmética de Shell es bastante capaz de evaluar condiciones enteras por sí sola. Raramente necesita demasiadas pruebas y / o tareas externas. Este
while
bucle duplica bastante bien tus bucles anidados:No se imprime tanto, por supuesto, no escribí mucho, pero, por ejemplo, establecer el límite máximo en 16 en lugar de 101 como se escribe arriba y ...
Definitivamente está haciendo el trabajo. Y requiere muy poco más para aproximar su salida:
Solo haciendo eso en lugar de la
echo
y ...Esto funciona
busybox
. Es muy portátil, rápido y fácil de usar.Su problema de subshell va a ocurrir en la mayoría de los shells, pero es, con mucho , el más agudo en un
bash
shell. Alternaba entre hacer... y la forma en que lo escribí arriba en varios shells para un techo de 101 y lo
dash
hice sin el subshell en .017 segundos y con el subshell en 1.8 segundos.busybox
.149 y 2, zsh .149 y 4,bash
.35 y 6, yksh93
en .149 y .160.ksh93
no se bifurca para subcapas como deben hacerlo las otras cáscaras. Entonces, tal vez el problema no sea tanto el subshell como el shell .fuente
[ "$((...))" -eq "$((...))" ]
más(( (...) == (...) ))
? ¿Es este último menos portátil?[ "$((...))" -eq "$((...)) ]
funciona en shells que no toman 15 segundos para ejecutar el programa, y el otro no. Si la ventaja de uno sobre otro es cuestionable, entonces eso solo puede darle ventaja al primero, lo que significa que nunca hay una buena razón para usar(( (...) == (...) ))
.(( ... ))
. Estoy halagado, pero yo sí no tienen ese conocimiento detallado. (Recuerde, yo soy el que acaba de preguntar si(( ... ))
es menos portátil). Así que realmente no puedo entender su respuesta. : - / ¿Podría ser un poco más explícito?"$((...))"
está especificado por POSIX y el otro es una extensión de shell. Los proyectiles POSIX son bastante capaces. Evendash
yposh
manejará correctamente las pruebas de rama como"$((if_true ? (var=10) : (var=5) ))"
y siempre se asignará$var
correctamente.busybox
se rompe allí: siempre evalúa ambos lados independientemente del$if_true
valor de '.