非線性方程求根
import numpy as np
def bisect(f, a, b, tol):
"""
:param f: 非線性函數
:param a: 區間左端點
:param b: 區間右端點
:param tol: 誤差容忍範圍
:return: 非線性函數在[a,b]上的根
"""
if np.sign(f(a) * f(b)) >= 0: # wrong input
print('f(a)f(b) <0 not satisfied')
return
fa = f(a)
fb = f(b)
while ((b - a) / 2) > tol:
c = (a + b)/2
fc = f(c)
if fc == 0: # c is a solution, done
return c
if np.sign(fc * fa) < 0: # new interval [a, c]
b = c
fb = fc
else: # new interval [c, b]
a = c
fa = fc
return (a + b)/2 # new midpoint is best estimate
def fixed_demo(g0, x0, n):
"""
:param g0: 迭代格式
:param x0: 初始迭代點
:param n: 迭代次數
:return: g(x)的不動點,即非線性方程的根
"""
x = np.zeros(n+1)
x[0] = x0
for i in range(n):
x[i+1] = g0(x[i])
return x
def newton_demo(f, f_der, x0, n):
"""
:param f: 非線性函數
:param f_der: 非線性函數的導數
:param x0: 初始迭代點
:param n: 迭代次數
:return: 非線性方程的根
"""
x = np.zeros(n+1)
x[0] = x0
for i in range(n):
x[i+1] = x[i] - (f(x[i]) / f_der(x[i]))
return x
def fun(x):
return x**3 + 2 * x**2 + 10 * x - 20
# return x**2 - 3 * x + 2 - np.exp(x)
def fun_der(x):
return 3 * x**2 + 4 * x + 10
# return 2 * x - 3 - np.exp(x)
def g(x):
# return (np.exp(x) - 2) / (x - 3)
return 20 / (x**2 + 2 * x + 10)
def demo(g0, f_der, f, n):
"""
:param g0: 不動點迭代法選取的迭代格式g(x)
:param f_der: 非線性函數的導數
:param f: 非線性函數
:param n: 迭代次數
:return: NONE
"""
x_newton = newton_demo(f, f_der, 1.5, n)
x_fixed = fixed_demo(g0, 1.5, n)
x_ref = bisect(f, 1, 2, 1.e-14)
print('Reference Solution: ', x_ref)
print("Newton iteration method")
print(' no. solution error bound error')
for i in range(n):
print("%3d %14.12f %7.2e %7.2e" %
(i, x_newton[i], np.abs(x_newton[i+1] - x_newton[i]), np.abs(x_ref - x_newton[i])))
print("")
print("Fixed point iteration method")
print(' no. solution error bound error')
for i in range(n):
print("%3d %14.12f %7.2e %7.2e" %
(i, x_fixed[i], np.abs(x_fixed[i+1] - x_fixed[i]), np.abs(x_ref - x_fixed[i])))
if __name__ == '__main__':
demo(g, fun_der, fun, 11)
運行結果:
reference solution是通過二分法得到的精度較高的解來代替