# -*- 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
#######################################
# f分布の計算(P(X = ff), P(X < ff))
# dd : P(X = ff)
# df1,df2 : 自由度
# return : P(X < ff)
#######################################
def f(ff, dd, df1, df2) :
if ff < 1.0e-10 :
ff = 1.0e-10
x = ff * df1 / (ff * df1 + df2)
if df1%2 == 0 :
if df2%2 == 0 :
u = x * (1.0 - x)
pp = x
ia = 2
ib = 2
else :
u = 0.5 * x * sqrt(1.0-x)
pp = 1.0 - sqrt(1.0-x)
ia = 2
ib = 1
else :
if df2%2 == 0 :
u = 0.5 * sqrt(x) * (1.0 - x)
pp = sqrt(x)
ia = 1
ib = 2
else :
u = sqrt(x*(1.0-x)) / pi
pp = 1.0 - 2.0 * atan2(sqrt(1.0-x), sqrt(x)) / pi
ia = 1
ib = 1
if ia != df1 :
for i1 in range(ia, df1-1, 2) :
pp -= 2.0 * u / i1
u *= x * (i1 + ib) / i1
if ib != df2 :
for i1 in range(ib, df2-1, 2) :
pp += 2.0 * u / i1
u *= (1.0 - x) * (i1 + df1) / i1
dd[0] = u / ff
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 f, gamma, normal, bisection, newton
############################
# f分布の計算
# 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)(関数値, f 分布)
#######################################
def f_f(x) :
y = np.empty(1, np.float)
return f(x, y, dof1, dof2) - 1.0 + p
#################################
# P(X = x)(関数の微分, f 分布)
#################################
def f_df(x) :
y = np.empty(1, np.float)
z = f(x, y, dof1, dof2)
return y[0]
######################################
# f分布のp%値(P(X > u) = 0.01p)
# ind : >= 0 : normal(収束回数)
# = -1 : 収束しなかった
######################################
def p_f(ind) :
MAX = 340
ff = 0.0
sw = 0
# 初期値計算の準備
# while文は,大きな自由度によるガンマ関数の
# オーバーフローを避けるため
while sw >= 0 :
df1 = 0.5 * (dof1 - sw)
df2 = 0.5 * dof2
a = 2.0 / (9.0 * (dof1 - sw))
a1 = 1.0 - a
b = 2.0 / (9.0 * dof2)
b1 = 1.0 - b
yq = p_normal(ind)
e = b1 * b1 - b * yq * yq
if e > 0.8 or dof1+dof2-sw <= MAX :
sw = -1
else :
sw += 1
if (dof1-sw) == 0 :
sw = -2
if sw == -2 :
ind[0] = -1
else :
# f0 : 初期値
if e > 0.8 :
x = (a1 * b1 + yq * sqrt(a1*a1*b+a*e)) / e
f0 = x ** 3.0
else :
y1 = float(dof2) ** (df2-1.0)
y2 = float(dof1) ** df2
x = gamma(df1+df2, ind) / gamma(df1, ind) / gamma(df2, ind) * 2.0 * y1 / y2 / p
f0 = x ** (2.0/dof2)
# ニュートン法
ff = newton(f_f, f_df, f0, 1.0e-6, 1.0e-10, 100, ind)
return ff
# 密度関数と分布関数の値
s = input("自由度1は? ")
dof1 = int(s)
s = input("自由度2は? ")
dof2 = 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 = f(x, z, dof1, dof2)
print("P(X = " + str(x) + ") = " + str(z[0]) + ", P( X < " + str(x) + ") = " + str(y) + "(自由度 = " + str(dof1) + ", " + str(dof2) + ")")
# グラフ出力
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 = f(x, z, dof1, dof2)
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(dof1) + ", " + str(dof2) + ")")
elif (1.0-p)< 1.0e-7 :
print(str(x) + "%値 = 0 (自由度 = " + str(dof1) + ", " + str(dof2) + ")")
else :
ind = np.empty(1, np.int)
y = p_f(ind)
print(str(x) + "%値 = " + str(y) + " 収束 " + str(ind[0]) + " (自由度 = " + str(dof1) + ", " + str(dof2) + ")")