実係数代数方程式の解(ベアストウ法)

# -*- coding: UTF-8 -*-
from math import *
import numpy as np

############################################
# 実係数代数方程式の解(ベアストウ法)
#      n : 次数
#      ct : 最大繰り返し回数
#      eps : 収束判定条件
#      p0, q0 : x2+px+qにおけるp,qの初期値
#      a : 係数(最高次から与え,値は変化する)
#      b,c : 作業域((n+1)次の配列)
#      r : 結果
#      k : 結果の位置
#      return : =0 : 正常
#               =1 : 収束せず
#      coded by Y.Suganuma
############################################

def Bairstow(n, ct, eps, p0, q0, a, b, c, r, k) :

	p1    = p0
	p2    = 0.0
	q1    = q0
	q2    = 0.0
	ind   = 0
	count = 0
			# 1次の場合
	if n == 1 :
		if abs(a[0]) < eps :
			ind = 1
		else :
			r[k] = complex(-a[1] / a[0], 0)
			# 2次の場合
	elif n == 2 :
				# 1次式
		if abs(a[0]) < eps :
			if abs(a[1]) < eps :
				ind = 1
			else :
				r[k] = complex(-a[2] / a[1], 0)
				# 2次式
		else :
			D = a[1] * a[1] - 4.0 * a[0] * a[2]
			if D < 0.0 :   # 虚数
				D      = sqrt(-D)
				a[0]  *= 2.0
				r[k]   = complex(-a[1] / a[0], D / a[0])
				r[k+1] = complex(-a[1] / a[0], -D / a[0])
			else :   # 実数
				D      = sqrt(D)
				a[0]   = 1.0 / (2.0 * a[0])
				r[k]   = complex(a[0] * (-a[1] + D), 0)
				r[k+1] = complex(a[0] * (-a[1] - D), 0)
				# 3次以上の場合
	else :
					# 因数分解
		ind = 1
		while ind > 0 and count <= ct :
			for i1 in range(0, n+1) :
				if i1 == 0 :
					b[i1] = a[i1]
				elif i1 == 1 :
					b[i1] = a[i1] - p1 * b[i1-1]
				else :
					b[i1] = a[i1] - p1 * b[i1-1] - q1 * b[i1-2]
			for i1 in range(0, n+1) :
				if i1 == 0 :
					c[i1] = b[i1]
				elif i1 == 1 :
					c[i1] = b[i1] - p1 * c[i1-1]
				else :
					c[i1] = b[i1] - p1 * c[i1-1] - q1 * c[i1-2]
			D = c[n-2] * c[n-2] - c[n-3] * (c[n-1] - b[n-1])
			if fabs(D) < eps :
				return ind
			else :
				dp = (b[n-1] * c[n-2] - b[n] * c[n-3]) / D
				dq = (b[n] * c[n-2] - b[n-1] * (c[n-1] - b[n-1])) / D
				p2 = p1 + dp
				q2 = q1 + dq
				if abs(dp) < eps and fabs(dq) < eps :
					ind = 0
				else :
					count += 1
					p1 = p2
					q1 = q2

		if ind == 0 :
					# 2次方程式を解く
			D = p2 * p2 - 4.0 * q2
			if D < 0.0 :   # 虚数
				D      = sqrt(-D)
				r[k]   = complex(-0.5 * p2, 0.5 * D)
				r[k+1] = complex(-0.5 * p2, -0.5 * D)
			else :   # 実数
				D      = sqrt(D)
				r[k]   = complex(0.5 * (-p2 + D), 0)
				r[k+1] = complex(0.5 * (-p2 - D), 0)
					# 残りの方程式を解く
			n -= 2
			for i1 in range(0, n+1) :
				a[i1] = b[i1]
			ind = Bairstow(n, ct, eps, p0, q0, a, b, c, r, k+2)

	return ind

----------------------------------

# -*- coding: UTF-8 -*-
import numpy as np
from math import *
from function import Bairstow

############################################
# 代数方程式の解(ベアストウ法)
#      例:(x+1)(x-2)(x-3)(x2+x+1)
#           =x5-3x4-2x3+3x2+7x+6=0
#      coded by Y.Suganuma
############################################
			# データの設定
ct  = 1000
eps = 1.0e-10
p0  = 0.0
q0  = 0.0
n   = 5
a   = np.array([1.0, -3.0, -2.0, 3.0, 7.0, 6.0])
b   = np.empty(n+1, np.float)
c   = np.empty(n+1, np.float)
r   = np.empty(n, np.complex)
			# 計算
ind = Bairstow(n, ct, eps, p0, q0, a, b, c, r, 0)
			# 出力
if ind > 0 :
	print("収束しませんでした!")
else :
	for i1 in range(0, n) :
		print("   " + str(r[i1]))