Numeric-Data

bc scale:如何避免四捨五入?(計算小二項式機率)

  • December 15, 2019

以下程式碼計算 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 位十進制數字的給定精度列印輸出?

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。我在 Bash 腳本中編寫了一個完整的腳本作為此處的文件,而不僅僅是將命令通過管道傳輸到bcvia ,因為這樣可以輕鬆地將參數從 Bash 傳遞到.echo``bc``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

介紹

假設您要計算 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 個位置,但有這些尾隨0s

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

原因

計算的第一部分精確到小數點後 2 位,其餘部分被截斷。 在此處輸入圖像描述 在此處輸入圖像描述


解決方案

理想的解決方案是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表示精確到小數點後 2 位(如scale=2))。
printf '%.2f\n' "$(bc -l <<< '(7/116)*100')"
**6.03**

awk

  1. 僅供參考:awk也可以做算術
  2. 我認為echo以某種方式打破了互動循環。可能有更好的方法來做到這一點。
  3. 它不能讓您控制浮點數。我相信它可以以某種方式完成。
echo | awk '{print 100*(7/116)}'
**6.03448**

引用自:https://unix.stackexchange.com/questions/219013