以下代码计算 n 次试验中 k 次成功事件的二项式概率:
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(而不是“0.03566482”),而输入“4”时,结果显示为“.07261898”。
如何以 8 位十进制数字的给定精度打印输出,而不获取输出的四舍五入值?
答案1
简介
假设您想计算 7 占 116 的百分比。
您只需将 7 除以 116,然后将结果乘以 100。结果
应该如下所示:
bc -l <<< '(7/116)*100'
6.03448275862068965500
问题
您希望它精确到小数点后两位,因此您添加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
原因
解决方案
理想的解决方案是bash
/sh
原生支持浮点计算。为什么他们还没有这样做呢?我不知道。不这样做似乎很愚蠢。在那之前你可以用这些:
公元前
- 定义一个变量。
- 设置
scale
. - 除以 1。
bc -l <<< "x=(7/116)*100; scale=2; x/1"
6.03
打印函数
bc
将命令用"$(
...括起来)"
以进行命令替换。- 将其传递给
printf
. %.2f
在格式字符串中使用(%f
表示浮点数,.2
表示精确到小数点后两位(如scale=2
))。
printf '%.2f\n' "$(bc -l <<< '(7/116)*100')"
6.03
awk
- 仅供参考:
awk
也可以做算术 - 我认为
echo
以某种方式打破了交互循环。可能有更好的方法来做到这一点。 - 它不能让您控制浮点。我确信它可以以某种方式完成。
echo | awk '{print 100*(7/116)}'
6.03448
答案2
FWIW,
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)}'