# -*- coding: UTF-8 -*- from math import * import numpy as np ############################################ # Γ(x)の計算(ガンマ関数,近似式) # ier : =0 : normal # =-1 : x=-n (n=0,1,2,・・・) # return : 結果 # coded by Y.Suganuma ############################################ def gamma(x, ier) : ier[0] = 0 if x > 5.0 : v = 1.0 / x s = ((((((-0.000592166437354 * v + 0.0000697281375837) * v + 0.00078403922172) * v - 0.000229472093621) * v - 0.00268132716049) * v + 0.00347222222222) * v + 0.0833333333333) * v + 1.0 g = 2.506628274631001 * exp(-x) * pow(x,x-0.5) * s else : err = 1.0e-20 w = x t = 1.0 if x < 1.5 : if x < err : k = int(x) y = float(k) - x if abs(y) < err or abs(1.0-y) < err : ier[0] = -1 if ier[0] == 0 : while w < 1.5 : t /= w w += 1.0 else : if w > 2.5 : while w > 2.5 : w -= 1.0 t *= w w -= 2.0 g = (((((((0.0021385778 * w - 0.0034961289) * w + 0.0122995771) * w - 0.00012513767) * w + 0.0740648982) * w + 0.0815652323) * w + 0.411849671) * w + 0.422784604) * w + 0.999999926 g *= t return g ################################################ # 標準正規分布N(0,1)の計算(P(X = x), P(X < x)) # w : P(X = x) # return : P(X < x) ################################################ def normal(x, w) : # 確率密度関数(定義式) w[0] = exp(-0.5 * x * x) / sqrt(2.0*pi) # 確率分布関数(近似式を使用) y = 0.70710678118654 * abs(x) z = 1.0 + y * (0.0705230784 + y * (0.0422820123 + y * (0.0092705272 + y * (0.0001520143 + y * (0.0002765672 + y * 0.0000430638))))) P = 1.0 - z ** (-16.0) if x < 0.0 : P = 0.5 - 0.5 * P else : P = 0.5 + 0.5 * P return P ################################################ # t分布の計算(P(X = tt), P(X < tt)) # (自由度が∞の時の値はN(0,1)を利用して下さい) # dd : P(X = tt) # df : 自由度 # return : P(X < tt) ################################################ def t(tt, dd, df) : if tt < 0.0 : sign = -1.0 else : sign = 1.0 if abs(tt) < 1.0e-10 : tt = sign * 1.0e-10 t2 = tt * tt x = t2 / (t2 + df) if df%2 != 0 : u = sqrt(x*(1.0-x)) / pi p = 1.0 - 2.0 * atan2(sqrt(1.0-x), sqrt(x)) / pi ia = 1 else : u = sqrt(x) * (1.0 - x) / 2.0 p = sqrt(x) ia = 2 if ia != df : for i1 in range(ia, df-1, 2) : p += 2.0 * u / i1 u *= ((1.0 + i1) / i1 * (1.0 - x)) dd[0] = u / abs(tt) pp = 0.5 + 0.5 * sign * p return pp ############################################ # 二分法による非線形方程式(f(x)=0)の解 # fn : f(x)を計算する関数名 # x1,x2 : 初期値 # eps1 : 終了条件1(|x(k+1)-x(k)|<eps1) # eps2 : 終了条件2(|f(x(k))|<eps2) # max : 最大試行回数 # ind : 実際の試行回数 # (負の時は解を得ることができなかった) # return : 解 # coded by Y.Suganuma ############################################ def bisection(fn, x1, x2, eps1, eps2, max, ind) : x0 = 0.0 f1 = fn(x1) f2 = fn(x2) if f1*f2 > 0.0 : ind[0] = -1 else : ind[0] = 0 if f1*f2 == 0.0 : if f1 == 0.0 : x0 = x1 else : x0 = x2 else : sw = 0 while sw == 0 and ind[0] >= 0 : sw = 1 ind[0] += 1 x0 = 0.5 * (x1 + x2) f0 = fn(x0) if abs(f0) > eps2 : if ind[0] <= max : if abs(x1-x2) > eps1 and abs(x1-x2) > eps1*abs(x2) : sw = 0 if f0*f1 < 0.0 : x2 = x0 f2 = f0 else : x1 = x0 f1 = f0 else : ind[0] = -1 return x0 ############################################ # Newton法による非線形方程式(f(x)=0)の解 # fn : f(x)を計算する関数名 # dfn : f(x)の微分を計算する関数名 # x0 : 初期値 # eps1 : 終了条件1(|x(k+1)-x(k)|<eps1) # eps2 : 終了条件2(|f(x(k))|<eps2) # max : 最大試行回数 # ind : 実際の試行回数 # (負の時は解を得ることができなかった) # return : 解 # coded by Y.Suganuma ############################################ def newton(fn, dfn, x0, eps1, eps2, max, ind) : x1 = x0 x = x1 ind[0] = 0 sw = 0 while sw == 0 and ind[0] >= 0 : sw = 1 ind[0] += 1 g = fn(x1) if abs(g) > eps2 : if ind[0] <= max : dg = dfn(x1) if abs(dg) > eps2 : x = x1 - g / dg if abs(x-x1) > eps1 and abs(x-x1) > eps1*abs(x) : x1 = x sw = 0 else : ind[0] = -1 else : ind[0] = -1 return x ---------------------------------- # -*- coding: UTF-8 -*- import numpy as np import sys from math import * from function import t, gamma, normal, bisection, newton ############################ # t分布の計算 # coded by Y.Suganuma ############################ ########################################## # 1.0 - p - P(X>x)(関数値, 標準正規分布) ########################################## def normal_f(x) : y = np.empty(1, np.float) return 1.0 - p - normal(x, y) ################################################################ # 標準正規分布N(0,1)のp%値(P(X > u) = 0.01p)(二分法を使用) # ind : >= 0 : normal(収束回数) # = -1 : 収束しなかった ################################################################ def p_normal(ind) : u = bisection(normal_f, -7.0, 7.0, 1.0e-6, 1.0e-10, 100, ind) return u ####################################### # 1.0 - p - P(X > x)(関数値, t 分布) ####################################### def t_f(x) : y = np.empty(1, np.float) return t(x, y, dof) - 1.0 + p ################################# # P(X = x)(関数の微分, t 分布) ################################# def t_df(x) : y = np.empty(1, np.float) z = t(x, y, dof) return y[0] ################################################# # t分布のp%値(P(X > u) = 0.01p) # (自由度が∞の時の値はN(0,1)を利用して下さい) # ind : >= 0 : normal(収束回数) # = -1 : 収束しなかった ################################################# def p_t(ind) : tt = 0.0 pis = sqrt(pi) df = float(dof) df2 = 0.5 * df # 自由度=1 if dof == 1 : tt = tan(pi*(0.5-p)) else : # 自由度=2 if dof == 2 : if p > 0.5 : c = -1.0 else : c = 1.0 p2 = (1.0 - 2.0 * p) p2 *= p2 tt = c * sqrt(2.0 * p2 / (1.0 - p2)) # 自由度>2 else : yq = p_normal(ind) # 初期値計算のため if ind[0] >= 0 : x = 1.0 - 1.0 / (4.0 * df) e = x * x - yq * yq / (2.0 * df) if e > 0.5 : t0 = yq / sqrt(e) else : x = sqrt(df) / (pis * p * df * gamma(df2, ind) / gamma(df2+0.5, ind)) t0 = x ** (1.0/df) # ニュートン法 tt = newton(t_f, t_df, t0, 1.0e-6, 1.0e-10, 100, ind) return tt # 密度関数と分布関数の値 s = input("自由度は? ") dof = int(s) print("目的とする結果は? ") print(" =0 : 確率の計算( P(X = x) 及び P(X < x) の値)") s = input(" =1 : p%値( P(X > u) = 0.01p となるuの値) ") sw = int(s) z = np.empty(1, np.float) if sw == 0 : s = input("グラフ出力?(=1: yes, =0: no) ") sw = int(s) if sw == 0 : # 密度関数と分布関数の値 s = input(" データは? ") x = float(s) y = t(x, z, dof) print("P(X = " + str(x) + ") = " + str(z[0]) + ", P( X < " + str(x) + ") = " + str(y) + "(自由度 = " + str(dof) + ")") # グラフ出力 else : file1 = input(" 密度関数のファイル名は? ") file2 = input(" 分布関数のファイル名は? ") s = input(" データの下限は? ") x1 = float(s) s = input(" データの上限は? ") x2 = float(s) s = input(" 刻み幅は? ") h = float(s) out1 = open(file1, "w") out2 = open(file2, "w") x = x1 while x < x2+0.5*h : y = t(x, z, dof) out1.write(str(x) + " " + str(z[0]) + "\n") out2.write(str(x) + " " + str(y) + "\n") x += h out1.close() out2.close() # %値 else : s = input("%の値は? ") x = float(s) p = 0.01 * x if p < 1.0e-7 : print(str(x) + "%値 = ∞ (自由度 = " + str(dof) + ")") elif (1.0-p)< 1.0e-7 : print(str(x) + "%値 = -∞ (自由度 = " + str(dof) + ")") else : ind = np.empty(1, np.int) y = p_t(ind) print(str(x) + "%値 = " + str(y) + " 収束 " + str(ind[0]) + " (自由度 = " + str(dof) + ")")