在此之前,我們所舉的例子都可以透過人工手算的方式求解,但是當方程式很複雜該怎麼辦,如
這時可以透過數值分析來幫助我們求解,這裡我們無法去詳述所有的數值分析理論與方法,所以在此就大概介紹一下兩種方法,牛頓法與隨機搜尋法。
目標函數:
,令,求x,這樣複雜的函數很難用手算,求得一個解析解。此時,可以透過牛頓法來求得的值。
簡單來說就是,在解的附近,利用線性近似來逼近,亦即。此時,就是函數的近似解。
為了得到更好的近似,就會透過迭代的方式,找出更靠近解的近似值。作法如下,
令
解出
變量:
x(n) = n次迭代後的根的近似解
N = 迭代次數
Pseudo code:
For n = 1~ N:
end
Python
# 目標函數
def func(c, x):
return 200*c*math.exp(c*x)*(0.65 - 0.01*x) - 2*math.exp(c*x)-0.45
# 目標函數的一次導數
def der_func(c, x, h=0.01):
return (func(c, x+h) - func(c, x)) / h
N = 100 # 迭代次數
initial_param = 0.0 # 初始值
final_param = 0.0 # 終值
diff = 10e5 # 差異
c=0.025 # 參數
cnt = 0 # 達標次數
error = [] # 迭代過程差異的紀錄
while (abs(diff) >= 10e-5) and (cnt <= N):
f = func(c, initial_param)
diff_f = der_func(c, initial_param)
final_param = initial_param - (f/diff_f)
diff = final_param - initial_param
error.append(abs(diff))
initial_param = final_param
cnt += 1
print(final_param, cnt)
這方法比起牛頓法更加簡單,就是從解空間中隨機抽取N個點,去看哪個點離極值最近。此法的準確度跟抽取的點數個數有關,抽樣次數越多,越可能找到極值,但相對的也越花時間。
Python
def func(c, x):
return 200*c*math.exp(c*x)*(0.65 - 0.01*x) - 2*math.exp(c*x)-0.45
min_y = 10e5
N = 1000
threshold = 10e-5
c=0.025
final_x = 0
for i in range(N):
approx_x = random.uniform(10, 30)
approx_y = func(c, approx_x)
if abs(approx_y) < min_y:
min_y = abs(approx_y)
final_x = approx_x
print(final_x, min_y)
這裡只介紹了兩種單變量的數值方法,關於多變量及更多的數值求解法可以參考數值方法的教科書。