雖然向前差除和向後差除在計算順序上似乎有些不同,但對程式設計而言,事實上前差法和後差法是一樣的東西,只是表格輸出不同而已。說明圖如下所示。

NewtonForward2Backward.png 

 

/*
        Newton Forward and Backward Interpolation Algorithm
        Assume function is -4x^4 + 2x^3-3x^2+4x-1

        In fact, forward and backward is the same for Interpolation.
        If we use the 2 dim array to store the divided-difference value,
        we can find that the arrays of forward and backward are the same,
        just different display for the two arrays.

        事實上, 前除與後除是一樣的東西。若使用二維陣列儲存差分值,
        觀查其結果會發現,前除與後除之凍列是一樣的,只是顯示方式不同而已。

                                                                   -by EdisonX
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#define N 4

// 前差方式顯示
void ShowForward(double **f, unsigned n)
{
        unsigned i, j;
        printf("\n **** Show By Forward **** \n");
        for(i=0; i<n; i++){
                for(j=0; j<n-i; j++) printf("%5.0lf ", f[i][j]);
                printf("\n");
        }
}

// 後差方式顯示
void ShowBackward(double **f, unsigned n)
{
        unsigned i, j;
        printf("\n **** Show By Backward **** \n");
        for(i=0; i<n; i++){
                for(j=0; j<=i; j++) printf("%5.0lf ", f[i-j][j]);
                printf("\n");
        }
}

double func(double x)
{
        double sum=0.0;
        double x2=x*x, x3=x2*x,x4=x3*x;
        sum = -4*x4+2*x3-3*x2+4*x-1;
        return sum;
}

double NewtonInterpolation(double x,double *xn, double *yn, unsigned n)
{
        double mult=0.0;
        double **f; // 差分矩陣
        double P; // result
        unsigned i, j;

        // 配置記憶體
        f = (double**)malloc(sizeof(double*)*n);
        for(i=0; i<n; i++) f[i]=(double*)malloc(sizeof(double)*n);
        for(j=0; j<n; j++) f[j][0] = yn[j];

        // 建立差分表
        for(j=1; j<n; j++)
                for(i=0; i<n-j; i++)
                        f[i][j]= (f[i+1][j-1]-f[i][j-1])/(xn[i+j]-xn[i]);

        // 代入公式
        for(i=0, P=0.0; i<n; i++){
                for(j=0, mult=f[0][i]; j<i && mult!=0.0; j++){
                        mult*=(x-xn[j]);
                }
                P+=mult;
        }

        // 顯示前差與後差表格
        ShowForward(f, n), ShowBackward(f, n), printf("\n");

        // 釋放記憶體
        for(i=0; i<n; i++) free(f[i]);
        free(f);
        return P;
}

int main()
{
        unsigned i;
        double x=1.5;

        double xn[N+1]={1.234, 3.782, 4.563, 5.987, -1.157};
        double yn[N+1];

        for(i=0; i<N+1; i++) yn[i]=func(xn[i]); // reference point
        printf("correct: %lf\n", func(x));
        printf("Newton: %lf\n",NewtonInterpolation(x, xn, yn, N+1));
        return 0;
}

 

執行結果

correct: -15.250000

 **** Show By Forward ****
   -6  -288  -241   -60    -4
 -739 -1089  -527   -51
-1589 -2251  -277
-4795  -668
  -20

 **** Show By Backward ****
   -6
 -739  -288
-1589 -1089  -241
-4795 -2251  -527   -60
  -20  -668  -277   -51    -4

Newton: -15.250000

edisonx 發表在 痞客邦 PIXNET 留言(0) 人氣()