Calculating rounded percentage in Shell Script without using “bc”

荒凉一梦 提交于 2019-12-18 14:40:36

问题


I'm trying to calculate percentage of certain items in Shell Script. I would like to round off the value, that is, if the result is 59.5, I should expect 60 and not 59.

item=30
total=70
percent=$((100*$item/$total))

echo $percent

This gives 42.

But actually, the result is 42.8 and I would to round it off to 43. "bc" does the trick, is there a way without using "bc" ?

I'm not authorized to install any new packages. "dc" and "bc" are not present in my system. It should be purely Shell, cannot use perl or python scripts either


回答1:


Use AWK (no bash-isms):

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



回答2:


Taking 2 * the original percent calculation and getting the modulo 2 of that provides the increment for rounding.

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

echo $percent
43

(tested with bash, ash, dash and ksh)

This is a faster implementation than firing off an AWK coprocess:

$ 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



回答3:


A POSIX-compliant shell script is restricted to integer arithmetic using the shell language ("only signed long integer arithmetic is required"), so a pure shell solution must emulate floating-point arithmetic:

item=30
total=70

percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
  • 100 * item / total yields the truncated result of the integer division as a percentage.
  • 1000 * item / total % 10 >= 5 ? 1 : 0 calculates the 1st decimal place, and if it is equal to or greater than 5, adds 1 to the integer result in order to round it up.
  • Note how there's no need to prefix variable references with $ inside an arithmetic expansion $((...)).

If - in contradiction to the premise of the question - use of external utilities is acceptable:


  • awk offers a simple solution, which, however, comes with the caveat that it uses true double-precision binary floating point values and may therefore yield unexpected results in decimal representation - e.g., try printf '%.0f\n' 28.5, which yields 28 rather than the expected 29):
awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
  • Note how -v is used to define variables for the awk script, which allows for a clean separation between the single-quoted and therefore literal awk script and any values passed to it from the shell.

  • By contrast, even though bc is a POSIX utility (and can therefore be expected to be present on most Unix-like platforms) and performs arbitrary-precision arithmetic, it invariably truncates the results, so that rounding must be performed by another utility; printf, however, even though it is a POSIX utility in principle, is not required to support floating-point format specifiers (such as used inside awk above), so the following may or may not work (and is not worth the trouble, given the simpler awk solution, and given that precision problems due to floating-point arithmetic are back in the picture):
# !! This MAY work on your platform, but is NOT POSIX-compliant:
# `-l` tells `bc` to set the precision to 20 decimal places, `printf '%.0f\n'`
# then performs the rounding to an integer.
item=20 total=70
printf '%.0f\n' "$(bc -l <<EOF
100 * $item / $total
EOF
)"



回答4:


The following is based upon my second answer, but with expr and back-ticks -- which (while perhaps abhorrent to most) can be adapted to work in even the most archaic shells natively:

item=30
total=70
percent=`expr 200 \* $item / $total % 2 + 100 \* $item / $total`

echo $percent
43


来源:https://stackoverflow.com/questions/24284460/calculating-rounded-percentage-in-shell-script-without-using-bc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!