統計関数のパーセント点     Last modified: May 15, 2002
# パーセント点を求める
# gxp, xxp, txp, fxp, abs を使用する

BEGIN {
    print pxg(0.05)       # 引数:上側確率
    print pxx(0.05, 1)    # 引数:上側確率,自由度
    print pxt(0.05, 100)  # 引数:両側確率,自由度
    print pxf(0.5, 1, 1)  # 引数:上側確率,自由度,自由度
}

# 正規分布のパーセント点を求める。

function pxg(p,     y, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
{
   a =  0.161614603871299e-15
   b = -0.178837229464158e-13
   c =  0.888943322341436e-12
   d = -0.261195052190738e-10
   e =  0.500533655324426e-09
   f = -0.646627744010232e-08
   g =  0.553751002988654e-07
   h = -0.283629174340630e-06
   i =  0.539877747512783e-06
   j =  0.122127251950965e-05
   k =  0.154574365345128e-04
   l = -0.234768842092152e-03
   m = -0.830686207721635e-03
   n =  0.370684581838722e-01
   o =  1.57079636931376
   y = -log(4*p*(1-p))
   return sqrt(((((((((((((((y*a+b)*y+c)*y+d)*y+e)*y+f)*y+g)*y+h)*y+i)*y \
          +j)*y+k)*y+l)*y+m)*y+n)*y+o)*y)
}

# カイ二乗分布のパーセント点を求める。

function pxx(p0, idf,     df9, temp, u, xl, xm, xr, ok)
{
   ok = 0
   xl = 0
   xr = 10
   while (xr < 1e30) {
       temp = xxp(xr, idf)
       if (temp == p0) {
           return xr
       }
       else if (temp < p0) {
           ok = 1
           break
       }
       xl = xr
       xr *= 10
   }
   
   if (ok == 0) {
       printf "pxx(1): 近似計算を行いました。" > "/dev/stderr"
       u = pxg(p0)
       df9 = 2/(9*idf)
       temp = 1-df9+u*sqrt(df9)
       return idf*temp^3
   }
   else {
       do {
           xm = (xl+xr)*0.5
           temp = xxp(xm, idf)
           if (temp > p0) {
               xl = xm
           }
           else {
               xr = xm
           }
       } while (abs(xr-xl)/xm > 1e-10)
       return xm
   }
}

# t分布のパーセント点を求める。

function pxt(p0, idf,     p9, u, u2, xl, xm, xr, ok)
{
   ok = 0
   
   if (p0 == 1) {
       return 0
   }
   
   xl = 0
   xr = 10
   while (xr < 1e30) {
       p9 = txp(xr, idf)
       if (p9 == p0) {
           return xr
       }
       else if (p9 < p0) {
           ok = 1
           break
       }
       xl = xr
       xr *= 10
   }
   
   if (ok == 0) {
       fprintf "pxt(1): 近似計算を行いました。" > "/dev/stderr"
       u = pxg(p0/2)
       u2 = u*u
       return u + ((u2+1.0)*u)/(4.0*idf)
              + (((5*u2+16)*u2+3)*u)/(96*idf^2)
              + ((((3*u2+19)*u2+17)*u2-15)*u)/(384*idf^3)
   }
   else {
       do {
           xm = (xl+xr)*0.5
           p9 = txp(xm, idf)
           if (p9 > p0) {
               xl = xm
           }
           else {
               xr = xm
           }
       } while (abs(xr-xl)/xm > 1e-10)
       return xm
   }
}

# F分布のパーセント点を求める。

function pxf(p0, df1, df2,     p9, xl, xm, xr, c, temp, ok)
{
   ok = 0
   
   xl = 0
   xr = 10
   while (xr < 1e30) {
       p9 = fxp(xr, df1, df2)
       if (p9 == p0) {
           return xr
       }
       else if (p9 < p0) {
           ok = 1
           break
       }
       xl = xr
       xr *= 10
   }
   
   if (ok == 0) {
       if (df1 > df2) {
           temp = df1
           df1 = df2
           df2 = temp
           p0 = 1-p0
           ok = 1
       }
       if (df1 == 1) {
           c = pxt(p0, df2)
           c = c*c
       }
       else {
           temp = df1-2.0
           printf "pxf(1): 近似計算を行いました。" > "/dev/stderr"
           c = pxx(p0, df1)
           c = c/df1*(1+ (c-temp)*0.5/df2 + (4*c*c-11*temp*c \
               +temp*(7*df1-10))/(24*df2^2)+(2*c^3-10*temp*c*c \
               +temp*(17*df1-26)*c-(df1-2)*temp*(9*df1-6))/(48*df2^3))
       }
       return (ok == 1 && c != 0) ? 1/c : c
   }
   
   do {
       xm = (xl+xr)*0.5
       p9 = fxp(xm, df1, df2)
       if (p9 > p0) {
           xl = xm
       }
       else {
           xr = xm
       }
   } while (abs(xr-xl)/xm > 1e-10)
   
   return xm
}

# 正規分布の上側確率

function gxp(x,    is, i, c, p, y, z, pi2)
{
   pi2 = 0.398942280401432677940
   
   is = -1
   y = abs(x)
   c = y*y
   p = 0.0
   z = exp(-c*0.5)*pi2
   if (y < 2.5) {
       for (i = 20; i > 0; i--) {
           p = i*c/(i*2+1+is*p)
           is = -is
       }
       p = 0.5-z*y/(1.0-p)
   }
   else {
       for (i = 20; i > 0; i--) {
           p = i/(y+p)
       }
       p = z/(y+p)
   }
   return (x < 0.0) ? 1.0-p : p
}

# カイ二乗分布の上側確率

function xxp(x, is,     i, t, w, pi2)
{
   pi2 = 0.398942280401432677940
   if (x == 0.0) {
       return 1
   }
   else if (is == 1) {
       return gxp(sqrt(x))*2.0
   }
   else if (is == 2) {
       return exp(-x/2.0)
   }
   else if ((is%2) == 0) {
       w = t = 1.0
       for (i = 2; i <= is-2; i += 2) {
           t *= x/i
           w += t
       }
       return exp(log(w) - x*0.5)
   }
   else {
       t = w = sqrt(x)
       for (i = 3; i <= is-2; i += 2) {
           t *= x/i
           w += t
       }
       return 2.0*(gxp(sqrt(x))+pi2*exp(log(w)-x*0.5))
   }
}

# t分布の両側確率 <a name="txp">txp.awk</a>

function txp(t, df,    i, t1, t2, p, w, m2pi)
{
   m2pi = 0.636619772367581343076
   t1 = abs(t)/sqrt(df)
   t2 = 1.0/(1.0+t1*t1)
   if ((df%2) == 0) {
       w = t1*sqrt(t2)
       p = 1.0-w
       for (i = 2; i <= df-2; i += 2) {
           p -= w *= t2*(i-1)/i
       }
   }
   else {
       p = 1.0-m2pi*atan2(t1, 1)
       if (df >= 3) {
           w = m2pi*t1*t2
           p -= w
           for (i = 3; i <= df-2; i += 2) {
               p -= w *= t2*(i-1)/i
           }
       }
   }
   return (p < 0.0 && abs(p) < 1e-10) ? 0.0 : p
}

# F分布の上側確率 <a name="fxp">fxp.awk</a>

function fxp(f, df1, df2,     i1, i2, c, p, s, w, y, m2pi)
{
   m2pi = 0.636619772367581343076
   m_pi = 3.14159265358979323846
   i1 = 2-(df1%2)
   i2 = 2-(df2%2)
   w = df2/(df2+df1*f)
   y = 1.0-w
   p = sqrt(w)
   s = sqrt(y)
   if (2*i1-i2 == 0) {
       p = 1.0-s
       c = s*w/2.0
   }
   else if (2*i1-i2 == 1) {
       c = s*p/m_pi
       p = 1.0-atan2(s, p)*m2pi
   }
   else if (2*i1-i2 == 2) {
       p = w
       c = w*y
   }
   else {
       c = y*p/2.0
   }
   for (; df2 > i2; i2 += 2) {
       p -= 2.0/i2*c
       c *= w*(i1+i2)/i2
   }
   for (; df1 > i1; i1 += 2) {
       p += 2.0/i1*c
       c *= y*(i1+i2)/i1
   }
   return (p < 0.0 && abs(p) < 1e-10) ? 0.0 : p
}

# x の絶対値を求める
# 使用例: x = abs(-10.95)

function abs(x)
{
   return (x < 0) ? -x : x
}

・ 直前のページへ戻る  ・ E-mail to Shigenobu AOKI