數值分析讀書筆記(4)求非線性方程的數值求解
1.關於非線性方程的根的定位以及二分法
我們直接介紹二分法
將有根區間 用中點 將它平分, 如果 不是 的零點, 則再做搜索, 檢查 和 是否同號, 然後即可知根落在左側還是右側, 用這個中點來代替掉原來的端點, 然後得到一個新的區間, 如此反覆迭代下去之後, 我們會發現區間收斂到接近一個數
二分法簡單易懂,我們只要不斷去計算中點,然後判斷符號,從而來判斷根的位置
但是二分法有着收斂速度慢的缺點,我們一般是用二分法來找到一個合適的初始值,然後再用其他收斂速度比較快的算法進行計算
我們可以用代碼來實現一下二分法
public class NumericalTest {
public static void main(String[] args){
double a=0,b=2,mid=(a+b)/2,fa,fb,fmid;
for(int i=0;i<100;i++){
System.out.println(mid);
fa=function(a);
fb=function(b);
fmid=function(mid);
if(fa*fmid>0){
a=mid;
}else{
b=mid;
}
mid=(a+b)/2;
}
}
public static double function(double x){
return Math.pow(x,3)+2*Math.pow(x,2)-4;
}
}
給出最後的輸出結果
1.1303954347672787
1.1303954347672787
1.1303954347672787
1.1303954347672787
1.1303954347672787
1.1303954347672787
1.1303954347672787
2.基於不動點原理的迭代法
類似於之前關於迭代法求解線性方程組時所講過的Gauss-Seidel迭代以及Jacobi迭代等迭代的方法,我們對於非線性方程也可以使用這種基於不動點原理的迭代法,這時我們的目的即是構造出一個等價的非線性方程
我們用簡單的代碼來模擬一下
public class NumericalTest {
public static void main(String[] args){
double x=0;
for(int i=0;i<100;i++){
x=function(x);
System.out.println(x);
}
}
public static double function(double x){
return Math.sqrt((4-Math.pow(x,3))/2);
}
}
上面的代碼是對 進行轉換, 並且建立迭代格式
最後可以看出來應該是收斂的,給出最後的幾個輸出
1.1303954901953999
1.1303953877755042
1.130395474606742
1.1303954009915165
1.1303954634022533
1.1303954104906446
這裏給出不動點迭代的三個基本要求
- 適定性: 要保證序列 始終在 的定義域中,才能使迭代不中斷
- 收斂性: 要求迭代收斂
- 收斂率: 要求收斂速度儘可能高
接下來我們來研究一下不動點的存在性以及迭代法的全局收斂性
關於不動點的存在性,給出一個Lipschitz條件,且給出不動點存在與唯一性定理
設迭代函數 , 且同時滿足
1. 定義域條件: ,
2. Lipschitz條件:存在Lipschitz常數 ,使得對任意 有
則不動點迭代函數 在 上存在唯一的不動點
需要注意的是,這是不動點存在且唯一的一個充分條件,卻不是必要的,
也就是說如果不滿足這兩個條件或不滿足其中一個條件者,可能存在不動點
下面給出不動點迭代收斂與誤差估計的定理
設迭代函數 滿足上述的定義域條件以及Lipschitz條件,則對任意的 , 由不動點迭代格式產生的序列 必收斂於 的不動點 ,並有誤差估計
上述兩個不等式,有時稱前者爲先驗估計,後者爲後驗估計
利用上面的不等式,我們可以計算出給定誤差界限所需要迭代的步數
其中 爲給定的誤差界限
給出一個推論
設迭代函數 , 在 上有界,且
則之前給出的不動點唯一定理以及後續的收斂定理均成立
以上給出的條件可能是基於全局收斂的,如果滿足的條件只是限制在某個領域之中的話,那麼就是局部收斂,對於局部收斂,也只需證明局部滿足上述條件,需要提一下的是,不動點的迭代方案,在全局的情況下屬於線性收斂
3.Newton切線法
解非線性方程組,除了我們之前講述的迭代法以及二分法,還有Newton切線法,這一種方法是解非線性方程組常用的有效方法,特別的,當初始值充分接近方程的根的時候,收斂的很快,基本思想是以直代曲,近似成線性方程來求解,下面給出迭代的格式
這裏直接給出代碼來進行模擬
public class NumericalTest {
public static void main(String[] args){
double x=1;
for(int i=0;i<20;i++){
System.out.println(x);
x=x-(function(x)/function2(x));
}
}
public static double function(double x){
return Math.pow(x,3)+2*Math.pow(x,2)-4;
}
//求導後的函數
public static double function2(double x){
return 3*Math.pow(x,2)+4*Math.pow(x,2);
}
}
比起二分法或者迭代法,它的收斂速度還是較爲快速的,特別是當初始值接近根的情況,更加明確的說,Newton切線在充分接近單根的情況下二次收斂,其他情況下線性收斂,充分接近重根的情況下線性收斂
下面針對Newton切線需要計算導數的這一缺點,給出另外一種類似的方法,即割線法
這裏直接給出迭代的格式
給出代碼的實現
public class NumericalTest {
public static void main(String[] args){
double x1=1,x2=0,temp;
for(int i=0;i<20;i++){
System.out.println(x2);
temp=x2;
x2=x2-(x2-x1)*(function(x2)/(function(x2)-function(x1)));
x1=temp;
}
}
public static double function(double x){
return Math.pow(x,3)+2*Math.pow(x,2)-4;
}
}
割線法的速度也是十分快,而且避免了導數的運算
對於非線性方程求根還有同倫算法,擬牛頓法等,待補充