Saltar al contenido

Cálculo del porcentaje redondeado en Shell Script sin usar “bc”

Esta noticia ha sido analizado por especialistas para que tengas la seguridad de la veracidad de nuestro contenido.

Solución:

Use AWK (sin bash-ismos):

item=30
total=70
percent=$(awk "BEGIN  pc=100*$item/$total; i=int(pc); print (pc-i<0.5)?i:i+1 ")

echo $percent
43

Tomando 2 * el cálculo de porcentaje original y obteniendo el módulo 2 de eso proporciona el incremento para el redondeo.

item=30
total=70
percent=$((200*$item/$total % 2 + 100*$item/$total))

echo $percent
43

(probado con bash, ash, dash y ksh)

Esta es una implementación más rápida que disparar un coproceso AWK:

$ pa()  for i in `seq 0 1000`; do pc=$(awk "BEGIN  pc=100*$item/$total; i=int(pc); print (pc-i<0.5)?i:i+1 "); done; 
$ time pa

real    0m24.686s
user    0m0.376s
sys     0m22.828s

$ pb()  for i in `seq 0 1000`; do pc=$((200*$item/$total % 2 + 100*$item/$total)); done; 
$ time pb

real    0m0.035s
user    0m0.000s
sys     0m0.012s

Solo se requiere un script de shell compatible con POSIX para admitir entero aritmética usando el lenguaje de concha ("solo se requiere aritmética de enteros largos con signo"), por lo que un cáscara pura la solución debe emular aritmética de coma flotante[1]:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total produce el truncado resultado de la entero división como un porcentaje.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 calcula el 1er decimal, y si es igual o mayor a 5, suma 1 al resultado entero para redondearlo.
  • Tenga en cuenta cómo hay no Necesitar prefix referencias variables con $ dentro de una expansión aritmética $((...)).

Si, en contradicción con la premisa de la pregunta, el uso de utilidades externas es aceptable:


  • awk ofrece una sencillo solución, que, sin embargo, viene con la consideración que usa true Precisión doble binario valores de punto flotante y, por lo tanto, puede producir resultados inesperados en decimal representación - por ejemplo, intente printf '%.0fn' 28.5cuyos rendimientos 28 en lugar de lo esperado 29):
awk -v item=30 -v total=70 'BEGIN  printf "%.0fn", 100 * item / total '
  • Tenga en cuenta cómo -v se utiliza para definir variables para el awk script, que permite una clara separación entre el entre comillas simples y por lo tanto literalawk script y cualquier valor que se le haya pasado desde el cáscara.

  • Por el contrario, aunque bces una utilidad POSIX (y, por lo tanto, se puede esperar que esté presente en la mayoría de las plataformas similares a Unix) y realiza precisión arbitraria aritmética, invariablemente trunca los resultados, por lo que redondeo debe ser realizado por otro utilidad; printfsin embargo, aunque en principio es una utilidad POSIX, es no requerido para admitir especificadores de formato de coma flotante (como los que se usan dentro awk arriba), por lo que el siguiente puede o no funcionar (y no vale la pena, dado el simple awk solución, y dado que los problemas de precisión debido a la aritmética de punto flotante están de vuelta en la imagen):
# !! This MAY work on your platform, but is NOT POSIX-compliant:
# `-l` tells `bc` to set the precision to 20 decimal places, `printf '%.0fn'`
# then performs the rounding to an integer.
item=20 total=70
printf '%.0fn' "$(bc -l <

[1] Sin embargo, POSIX permite soporte no entero "El shell puede usar un tipo flotante real en lugar de firmado siempre que no afecte los resultados en los casos en que no haya desbordamiento". En la práctica, ksh y zsh. admite aritmética de coma flotante si lo solicitaspero no bash y dash. Si desea ser compatible con POSIX (ejecutar a través de /bin/sh), siga con la aritmética de enteros. En todos los shells, la división de enteros funciona como de costumbre: el cociente se devuelve, que es el resultado de la división con cualquier parte fraccionaria truncada (eliminada).

valoraciones y comentarios

Si haces scroll puedes encontrar las observaciones de otros usuarios, tú de igual manera eres capaz mostrar el tuyo si te gusta.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *