1. 程式人生 > >數值分析實驗報告 Lab1 誤差的影響

數值分析實驗報告 Lab1 誤差的影響

數值分析實驗報告 Lab1 誤差的影響

一、問題引出

(一)問題例項:

利用 n n 階泰勒展開多項式 i =

0 n ( x i i !
) \sum\limits_{i=0}^n(\frac{x^i}{i!}) 計算函式 f ( x ) =
e x f(x)=e^x
在給定 x x 的值。要求絕對誤差在最大階數 M A X N = 20 MAXN=20 以內達到給定精度 E P S = 0.00001 EPS=0.00001 ,即使得 i = 0 n ( x i i ! ) e x < E P S \left|\sum\limits_{i=0}^n(\frac{x^i}{i!})-e^x\right|<EPS 並且 n < M A X N n<MAXN

(二)具體要求:

裁判輸入資料:

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 為給定點,函式返回達到精度要求的近似的值。常數 M A X N MAXN E P S EPS 在裁判程式中定義。若無法在 M A X N MAXN 次疊加內達到精度,則函式返回 -1。

二、分析與實踐

(一)問題分析

此處程式碼段重在 double Exp_Calculate( double x ) 的實現。
首先是程式碼模組流程的分析與建立。

  • 設定步:設定預設變數值 power=1.0(求和分子),factorial = 1.0(求和分母),sum=1.0(總和)
  • 過程步:不斷迭代得到 sum 值
  • 決策步:判斷 i = 0 n ( x i i ! ) e x &lt; E P S \left|\sum\limits_{i=0}^n(\frac{x^i}{i!})-e^x\right|&lt;EPS
(二)實驗分析

起初實現其實是個比較容易的過程。
但剛開始 程式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行以後,由於小數相近,導致相加負數或者說是相減時,小數的有效位數減少了,進而引發收斂速度變慢,最終不能得到想要的結果。而為了解決這種問題的發生,最好的方式就是防止負數的出現。

(三)解決方案

思路: i = 0 n ( x i i ! ) e x &lt; E P S \left|\sum\limits_{i=0}^n(\frac{x^i}{i!})-e^x\right|&lt;EPS ,由這個公式,或者說重點也就是看這個公式。

  1. 在式子中,可以發現 e x e^x 始終都為正數,但它存在一個等式 e x = 1 e x e^x=\frac{1}{e^{-x}} ,這個等式說明,當輸入為負數的時候,它的計算方式是將它倒數化,進而以正數的計算方式進行。這點值得注意。
  2. 繼續考慮 i = 0 n ( x i i ! ) \sum\limits_{i=0}^n(\frac{x^i}{i!}) ,可以發現,當輸入的 x x 為負數,那麼 i = 0 n ( x i i ! ) \sum\limits_{i=0}^n(\frac{x^i}{i!}) 這個式子裡的項有可能為正數,有可能為負數,進而會導致結果有損失,那麼相應的解決方案就是將它正數化。
  3. 具體而言,已知 e x = 1 e x e^x=\frac{1}{e^{-x}} 且當 n n 足夠大的時候, i = 0 n ( x i i ! ) e x = 1 e x \sum\limits_{i=0}^n(\frac{x^i}{i!})\approx e^x=\frac{1}{e^{-x}} ( 更詳細的是, e x = 1 e