BC 스케일: 반올림을 피하는 방법은 무엇입니까? (소이항 확률 계산)

BC 스케일: 반올림을 피하는 방법은 무엇입니까? (소이항 확률 계산)

다음 코드는 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개 위치까지 정확하지만 다음과 같은 후행 0s가 있습니다.

bc -l <<< 'scale=4; 100*(7/116)'
6.0300

이유

계산의 첫 번째 부분은 소수점 이하 두 자리까지 정확하고 나머지는 잘립니다. 여기에 이미지 설명을 입력하세요. 여기에 이미지 설명을 입력하세요.


해결책

이상적인 솔루션은 부동 소수점 계산을 기본적으로 지원하는 bash것 입니다. sh왜 아직까지 이 일을 하지 않았나요? 나는 모른다. 그렇게 하지 않는 것이 어리석은 것 같습니다. 그때까지는 다음을 사용할 수 있습니다.

기원전

  1. 변수를 정의합니다.
  2. 설정 scale.
  3. 1로 나눕니다.
bc -l <<< "x=(7/116)*100; scale=2; x/1"
6.03

인쇄 기능

  1. bc명령 대체를 위해 명령을 ...로 "$(묶습니다 )".
  2. 에 전달하세요 printf.
  3. %.2f형식 문자열에 사용됩니다( 소수점 이하 두 자리까지의 정확도를 나타내는 %f부동 소수점 숫자를 나타냄 .2(예: scale=2)).
printf '%.2f\n' "$(bc -l <<< '(7/116)*100')"
6.03

  1. 참고: awk연산도 할 수 있습니다
  2. echo상호작용 루프가 어떻게든 깨진 것 같아요 . 이를 수행하는 더 좋은 방법이 있을 수 있습니다.
  3. 부동 소수점을 제어할 수는 없습니다. 나는 그것이 어떻게든 이루어질 수 있다고 확신한다.
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다음과 같이 완전한 스크립트를 작성했습니다 .echobc여기문서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)}'

관련 정보