다음 코드는 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.03566482"가 아닌 0으로 표시되고, "4"를 입력하면 결과가 ".07261898"로 표시됩니다.
출력의 반올림 값을 가져오지 않고 십진수 8자리의 지정된 정밀도로 출력을 인쇄하려면 어떻게 해야 합니까?
답변1
소개
116에서 7의 백분율을 계산한다고 가정해 보겠습니다.
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
연산도 할 수 있습니다 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)}'