今天和朋友聊面經,說到一道題目,如何不用庫函數求根號,並且能用函數的輸入參數來控制誤差,他想了一個比較牛逼的方法,小數轉整數,然後二分尋找。在那麼短的時間想到這個地步真是不錯,但是我貌似記得科學計算的課上說過類似的東西,用泰勒計算:
其實想到了這個其他的都比較簡單了,貼一下代碼:
#include <iostream><br />#include <cmath><br />using namespace std;<br />#define _DEBUG<br />//(1+x)^t = 1+ t*x + t*(t-1)/(t!)8x^2+...+t*(t-1)(t-2)...(t-n+1)/(t!)*x^n<br />const double alpha = 0.5;<br />int main(int argc,char **argv)<br />{<br />if(argc!=2)<br />return 0;<br />double x,y, error = atof(argv[1]),<br />n = 1.0,//int最大隻能算12的階乘!<br />temp_a = alpha,<br />temp = 100.0;<br />cin>>y;<br />x = y-1;<br />y = 1.0;</p><p>int i = 1;<br />while(abs(temp) > error)<br />{<br />y+=temp_a/n*x;</p><p>n*=(i+1);<br />temp_a*=(alpha-i);<br />x*=x;<br />temp = temp_a/n*x;<br />++i;<br />}<br />cout<<"i= "<<i<<" Y = "<<y<<endl;<br />return 0;<br />}
但是可能是浮點數精度的問題,精度只能達到有限值,試一下long double結果一樣,只能精確到10e-4的量級,這個如何解決?
是哪裡計算的問題呢?再考慮一下!(當n過大時n!超出了double的表示範圍!)。
《九章算術》中有云:
開方術曰:置積為實。借一算,步之,超一等。議所得,以一乘所借一算為法,而以除。除已,倍法為定法。其複除,折法而下。複置借算,步之如初,以複議一乘之,所得副以加定法,以除。以所得副從定法。複除,折下如前。
因此代碼修正如下:
#include <iostream><br />#include <cmath><br />using namespace std;<br />#define _DEBUG<br />//(1+x)^t = 1+ t*x + t*(t-1)/(t!)8x^2+...+t*(t-1)(t-2)...(t-n+1)/(t!)*x^n<br />const double alpha = 0.5;<br />int main(int argc,char **argv)<br />{<br />if(argc!=2)<br />return 0;<br />double x,result, error = atof(argv[1]),//int最大隻能算12的階乘!<br />temp;<br />cin>>result;<br />//設定迴圈的初始值<br />x = result-1;<br />result = 1.0;<br />temp = alpha*x;<br />//設定迴圈次數統計變數<br />int i = 1;<br />while(abs(temp) > error)<br />{<br />result+=temp;<br />temp*=(alpha-i)/(i+1)*x;//霍納法則更新temp的值<br />++i;<br />}<br />cout<<"i= "<<i<<" Y = "<<result<<endl;<br />return 0;<br />}
整個問題的核心就在於如何使用泰勒級數,瞭解了公式,一切都比較好解決。
但是如果擴充這個問題,假定給定的是多項式,如何求根?使用泰勒級數逐項展開的前期工作量會變的很大,這時候需要考慮一下牛頓迭代了。
牛頓迭代的原理可以簡單敘述如下:
1。 對原始方程求導F1(假定方程有解)
2。 任取一點X0,求出曲線上的點(X0,Y0),並求出斜率F1(X0),作直線
3。 求出該直線和X軸的交點,並把新求出的X1作為新的迭代值
4。 重複1-3直到達到允許誤差
DONE~~