シェルスクリプトで特定のアイテムの割合を計算しようとしています。値を四捨五入したいと思います。つまり、結果が59.5の場合、59ではなく60を期待する必要があります。
item=30
total=70
percent=$((100*$item/$total))
echo $percent
これにより42が得られます。
しかし、実際には、結果は42.8であり、43に切り上げます。「bc」はトリックを行います。「bc」を使用しない方法はありますか?
新しいパッケージをインストールする権限がありません。 「dc」と「bc」は私のシステムに存在しません。純粋にシェルである必要があり、Perlまたはpythonスクリプトも使用できません
AWKを使用します(bash-ismなし):
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 *元のパーセント計算を取得し、そのモジュロ2を取得すると、丸めの増分が得られます。
item=30
total=70
percent=$((200*$item/$total % 2 + 100*$item/$total))
echo $percent
43
(bash、ash、dash、kshでテスト済み)
これは、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
POSIX準拠のシェルスクリプトは、シェル言語を使用した整数演算に制限されています( "符号付き長整数演算のみが必要です" )。 純粋なシェル解決策が必要エミュレート浮動小数点演算:
_item=30
total=70
percent=$(( 100 * item / total + (1000 * item / total % 10 >= 5 ? 1 : 0) ))
_
100 * item / total
_は、整数除算の結果を切り捨てパーセントで返します。1000 * item / total % 10 >= 5 ? 1 : 0
_は小数点第1位を計算し、それが5以上の場合、整数の結果に1を加算して切り上げます。$((...))
内で変数参照の前に_$
_を付ける必要があることに注意してください。-質問の前提に反して、外部ユーティリティの使用が許容される場合:
awk
はsimpleソリューションを提供しますが、これには真の倍精度を使用するcaveatが付属していますバイナリ浮動小数点値であるため decimal表現での予期しない結果 -たとえば、_printf '%.0f\n' 28.5
_ではなく_28
_を試してください予想される_29
_):_awk -v item=30 -v total=70 'BEGIN { printf "%.0f\n", 100 * item / total }'
_
-v
_を使用してawk
スクリプトの変数を定義する方法に注意してください。これにより、single-quotedとliteralawk
スクリプトと任意の値を明確に分離できます。 Shellから渡されます。bc
is POSIXユーティリティ (したがって、ほとんどのUnixライクなプラットフォームに存在することが期待される)およびarbitrary-precision算術演算、それは常に切り捨て結果であるため、丸めはanotherユーティリティによって実行する必要があります。ただし、 原理的にはPOSIXユーティリティです であるにもかかわらず、printf
は、浮動小数点形式指定子(上記のawk
内で使用されるような)をサポートするために不要です。 動作する場合も動作しない場合もある(より簡単なawk
ソリューションを考えると、トラブルの価値はなく、浮動小数点演算による精度の問題が戻ってきた):_# !! 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
)"
_
以下は私の2番目の回答に基づいていますが、exprおよびback-ticks-(おそらく大部分は嫌いですが)最も古風なものでも動作するように適合させることができますネイティブのシェル:
item=30
total=70
percent=`expr 200 \* $item / $total % 2 + 100 \* $item / $total`
echo $percent
43