次のコードは、n回の試行でk回の成功イベントの2項確率を計算します。
n=144
prob=$(echo "0.0139" | bc)
echo -e "Enter no.:"
read passedno
k=$passedno
nCk2() {
num=1
den=1
for((i = 1; i <= $2; ++i)); do
((num *= $1 + 1 - i)) && ((den *= i))
done
echo $((num / den))
}
binomcoef=$(nCk2 $n $k)
binprobab=$(echo "scale=8; $binomcoef*($prob^$k)*((1-$prob)^($n-$k))" | bc)
echo $binprobab
$passedno(=k) を "5" と入力すると結果は "0.03566482" ではなく 0 と表示され、 "4" と入力すると結果は ".07261898" と表示されます。
出力の丸め値を取得せずに10進数8桁の指定された精度で出力を印刷するにはどうすればよいですか?
答え1
はじめに
116から7のパーセンテージを計算するとします。
7を116で割り、その結果に100を掛けます。結果は
次のようになります。
bc -l <<< '(7/116)*100'
6.03448275862068965500
質問
小数点以下2桁まで正確にしたいので、scale=2;
次のように追加します。
bc -l <<< 'scale=2; 100*(7/116)'
6.00
値を上げようとしていますscale
。
bc -l <<< 'scale=3; 100*(7/116)'
6.000
何らかの理由でscale=4;
2つの位置まで正確ですが、次のような末尾の0
sがあります。
bc -l <<< 'scale=4; 100*(7/116)'
6.0300
理由
計算の最初の部分は小数点以下の2桁まで正確で、残りは切り捨てられます。
解決策
理想的な解決策は、浮動小数点計算を基本的にサポートするbash
ことです。sh
なぜまだこれをやっていないのですか?わかりません。そうしないのが愚かなようです。それまでは、次のものを使用できます。
紀元前
- 変数を定義します。
- 設定
scale
。 - 1で割ります。
bc -l <<< "x=(7/116)*100; scale=2; x/1"
6.03
印刷機能
bc
コマンドを置き換えるには、コマンドを...で"$(
囲みます)"
。- に渡してください
printf
。 %.2f
型文字列に使用されます(小数点以下の2桁までの精度を表す%f
浮動小数点数を表します.2
(例scale=2
:))。
printf '%.2f\n' "$(bc -l <<< '(7/116)*100')"
6.03
アッ
- 注:
awk
操作もできます echo
相互作用ループが何とか壊れていると思います。これを行うより良い方法があるかもしれません。- 浮動小数点を制御することはできません。私はそれが何とか成し遂げられると確信しています。
echo | awk '{print 100*(7/116)}'
6.03448
答え2
今後、
prob=$(echo "0.0139" | bc)
必要ありません - できます
prob=0.0139
例えば、
$ prob=0.0139; echo "scale=5;1/$prob" | bc
71.94244
アンダーフローの問題に加えて、コードに別の問題があります。 Bash算術は、nCk2
関数内の多数を処理するのに十分ではないかもしれません。たとえば、32ビットシステムでこの関数に10を渡すと、次のようになります。否定的な番号、-133461297271。
アンダーフローの問題を処理するには、他の回答で述べたように、より大きな計算を実行する必要があります。 OPに提供されているパラメータの場合、25〜30の範囲で十分です。
すべての算術演算を実行するようにコードを書き直しましたbc
。私はbc
次のように完全なスクリプトを作成しました。echo
bc
ここ文書Bashスクリプトでは、Bashからbc
。
#!/usr/bin/env bash
# Binomial probability calculations using bc
# Written by PM 2Ring 2015.07.30
n=144
p='1/72'
m=16
scale=30
bc << EOF
define ncr(n, r)
{
auto v,i
v = 1
for(i=1; i<=r; i++)
{
v *= n--
v /= i
}
return v
}
define binprob(p, n, r)
{
auto v
v = ncr(n, r)
v *= (1 - p) ^ (n - r)
v *= p ^ r
return v
}
sc = $scale
scale = sc
outscale = 8
n = $n
p = $p
m = $m
for(i=0; i<=m; i++)
{
v = binprob(p, n, i)
scale = outscale
print i,": ", v/1, "\n"
scale = sc
}
EOF
出力
0: .13345127
1: .27066174
2: .27256781
3: .18171187
4: .09021610
5: .03557818
6: .01160884
7: .00322338
8: .00077747
9: .00016547
10: .00003146
11: .00000539
12: .00000084
13: .00000012
14: .00000001
15: 0
16: 0
答え3
n=144
prob=$(echo "0.0139" | bc)
echo -e "Enter no.:"
read passedno
k=$passedno
nCk2() {
num=1
den=1
for((i = 1; i <= $2; ++i)); do
((num *= $1 + 1 - i)) && ((den *= i))
done
echo $((num / den))
}
binomcoef=$(nCk2 $n $k)
binprobab=$(echo "$binomcoef*($prob^$k)*((1-$prob)^($n-$k))" | bc -l)
printf "%0.8f\n" $binprobab
答え4
説明してくれた@voicesに感謝します。 awkとprintfを使用したソリューション:
awk 'BEGIN {printf("%.2f\n",100*7/116)}'