數值分析實驗報告 Lab1 誤差的影響
數值分析實驗報告 Lab1 誤差的影響
一、問題引出
(一)問題例項:
利用 階泰勒展開多項式 計算函式 在給定 的值。要求絕對誤差在最大階數 以內達到給定精度 ,即使得 並且 。
(二)具體要求:
裁判輸入資料:
1
2
3
4
5
-1
-2
-3
-4
-5
-6
標準輸出資料:
2.7183
7.3891
20.0855
54.5981
-1.0000
0.3679
0.1353
0.0498
0.0183
0.0067
0.0025
注意到第5組資料中,當 x=5 時,泰勒展開多項式前20項的和產生的誤差大於0.00005,達不到要求的精度0.00001,故應輸出-1.0000。
(三)裁判程式如下:
#include<stdio.h>
#include<math.h>
#define EPS 0.00001
#define MAXN 20
double Exp_Calculate( double x );
int main()
{
double x; /* 儲存輸入的浮點數x */
while (scanf("%lf", &x)!= EOF)
printf("%.4lf\n", Exp_Calculate(x));
return 0;
}
double Exp_Calculate( double x ){
/* 填寫程式碼段*/
}
Tips:函式介面定義:
double Exp_Calculate( double x )
,其中x
為給定點,函式返回達到精度要求的近似的值。常數 和 在裁判程式中定義。若無法在 次疊加內達到精度,則函式返回 -1。
二、分析與實踐
(一)問題分析
此處程式碼段重在 double Exp_Calculate( double x )
的實現。
首先是程式碼模組流程的分析與建立。
- 設定步:設定預設變數值 power=1.0(求和分子),factorial = 1.0(求和分母),sum=1.0(總和)
- 過程步:不斷迭代得到 sum 值
- 決策步:判斷
(二)實驗分析
起初實現其實是個比較容易的過程。
但剛開始 程式1.0版本 是這樣的:
double Exp_Calculate( double x ){
//預設值設定
double power=1.0;
double factorial = 1.0;
double sum=1.0;
int i;
//過程步求和
for(i=1;i<MAXN;i++){
//printf("sum[%d]=%lf\n",i,power/factorial);
power*=x;
factorial*=(double)i;
sum+=power/factorial;
}
//決策步終止
if(fabs(sum-exp(x))<EPS){return sum;}
else{return -1;}
}
測試:部分測試正確,但是當輸入-5的時候結果為-1。這就挺令人鬱悶的了。
接著為了找到問題,利用如下程式碼塊列印過程:
printf("sum[%d]=%lf\n",i,power/factorial);
結果顯示:
其實剛開始我還沒有緩過神來。經老師的指導,原來是在13行or14行以後,由於小數相近,導致相加負數或者說是相減時,小數的有效位數減少了,進而引發收斂速度變慢,最終不能得到想要的結果。而為了解決這種問題的發生,最好的方式就是防止負數的出現。
(三)解決方案
思路: ,由這個公式,或者說重點也就是看這個公式。
- 在式子中,可以發現 始終都為正數,但它存在一個等式 ,這個等式說明,當輸入為負數的時候,它的計算方式是將它倒數化,進而以正數的計算方式進行。這點值得注意。
- 繼續考慮 ,可以發現,當輸入的 為負數,那麼 這個式子裡的項有可能為正數,有可能為負數,進而會導致結果有損失,那麼相應的解決方案就是將它正數化。
- 具體而言,已知 且當 足夠大的時候, ( 更詳細的是,