t分布

# -*- 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) + ")")