數值分析

#include <stdio.h>
#include <math.h>
#include <iostream>
#define PrecisionLevel 1.0e-12 //迭代精度
double Z[6][6];//將Z聲明爲全局變量,便於後面操作
double** CreateMatrix(int m,int n);
void DestroyMatrix(double**A,int m,int n);
bool GaussElimination(double **A,int n,double* b);
double InfiniteNorm(double*b,int n);
void CoefficientMatrix(double* x,int m,double* y,int n,double** z,int k1,int k2,double** C);
double P_Value(double **C,int k,double x,double y);
double** SurfaceFitting(int& k);
//-----------------------------------------------
//生成一個m*n矩陣
double** CreateMatrix(int m,int n)
{
	double** A;
	int i;
	A=new double* [m];
	for(i=0;i<m;i++)
		A[i]=new double[n];
	return A;
}
//-----------------------------------------------
//釋放m*n矩陣
void DestroyMatrix(double** A,int m,int n)
{
	int i;
	for(i=0; i<m; i++)
		delete[]A[i];
	delete[]A;
}
//-----------------------------------------------
//列主元Guass削去法求解線性方程組,A*x=b
bool GaussElimination(double** A,int n,double* b)
{
	double m,sum,max,temp;
	int i,j,k,l;
	for(i=0; i<n-1; i++)
	{
		max=A[i][i];
		l=i;
		for(j=i; j<n; j++)  //尋找列主元
			if(fabs(A[i][j])>max)
			{
				max=fabs(A[i][j]);
				l=j;
			}
		if(l!=i)  //判斷並換行
		{
			for(j=i; j<n; j++)
			{
				temp=A[i][j];
				A[i][j]=A[l][j];
				A[l][j]=temp;
			}
			temp=b[i];
			b[i]=b[l];
			b[l]=temp;
		}
		if(A[i][i]==0)
		{
			printf("第%d個主元素爲0!\n",i);
			return false;
		}
		for(j=i+1; j<n; j++)  //消元
		{
			m=A[j][i]/A[i][i];
			for(k=i+1;k<n;k++)
				A[j][k]=A[j][k]-A[i][k]*m;
			b[j]=b[j]-b[i]*m;
		}
	}
	if(A[n-1][n-1]==0)
	{
		printf("第%d個主元素爲0!\n",n);
		return false;
	}
	//迴帶求解,用b來存儲解x
	b[n-1]=b[n-1]/A[n-1][n-1];
	for(i=n-2; i>=0; i--)
	{
		sum=0;
		for(j=i+1; j<n; j++)
			sum+=A[i][j]*b[j];
		b[i]=(b[i]-sum)/A[i][i];
	}
	return true;
}
//-----------------------------------------------
//計算向量的無窮範數
double InfiniteNorm(double* b,int n)
{
	double max;
	int i;
	max=b[0];
	for(i=1; i<n; i++)
	{
		if(fabs(b[i])>max)
			max=fabs(b[i]);
	}
	return max;
}
//-----------------------------------------------
//分片二次代數插值,z=z(u,t)
double PiecewiseInterpolation(double t,double u)
{
	double pnm=0.0;
	int i,j;
	bool flag=false;  //判斷t和u是否在插值區間內的標誌
	for(i=0; i<6; i++)
	{
		if((u>0.4*i-0.4/2)&&(u<=0.4*i+0.4/2))
			for(j=0;j<6;j++)
			{
				if((t>0.2*j-0.2/2)&&(t<=0.2*j+0.2/2))
				{
					flag=true;
					break;
				}
			}
		if(flag)
			break;
	}
	if(!flag)
	{
		printf("u=%e,t=%e is not in the expected interval\n",u,t);
		return 0;
	}

	if(i==0)  //邊界的處理
	{
		i=1;
		if(j==0)
			j=1;
		else if(j==5)
			j=4;
	}
	else if(i==5)
	{
		i=4;
		if(j==0)
			j=1;
		else if(j==5)
			j=4;
	}
	
	pnm=Z[j-1][i-1]*((u-0.4*i)*(u-0.4*(i+1))*(t-0.2*j)*(t-0.2*(j+1)))/((-0.4)*(-0.8)*(-0.2)*(-0.4))
		+Z[j][i-1]*((u-0.4*i)*(u-0.4*(i+1))*(t-0.2*(j-1))*(t-0.2*(j+1)))/((-0.4)*(-0.8)*(0.2)*(-0.2))
		+Z[j+1][i-1]*((u-0.4*i)*(u-0.4*(i+1))*(t-0.2*(j-1))*(t-0.2*j))/((-0.4)*(-0.8)*(0.2)*(0.4))
		+Z[j-1][i]*((u-0.4*(i-1))*(u-0.4*(i+1))*(t-0.2*j)*(t-0.2*(j+1)))/((-0.4)*(0.4)*(-0.2)*(-0.4))
		+Z[j][i]*((u-0.4*(i-1))*(u-0.4*(i+1))*(t-0.2*(j-1))*(t-0.2*(j+1)))/((-0.4)*(0.4)*(0.2)*(-0.2))
		+Z[j+1][i]*((u-0.4*(i-1))*(u-0.4*(i+1))*(t-0.2*(j-1))*(t-0.2*j))/((-0.4)*(0.4)*(0.2)*(0.4))
		+Z[j-1][i+1]*((u-0.4*(i-1))*(u-0.4*i)*(t-0.2*j)*(t-0.2*(j+1)))/((0.8)*(0.4)*(-0.2)*(-0.4))
		+Z[j][i+1]*((u-0.4*(i-1))*(u-0.4*i)*(t-0.2*(j-1))*(t-0.2*(j+1)))/((0.8)*(0.4)*(0.2)*(-0.2))
		+Z[j+1][i+1]*((u-0.4*(i-1))*(u-0.4*i)*(t-0.2*(j-1))*(t-0.2*j))/((0.8)*(0.4)*(0.2)*(0.4));
	return pnm;
}
//-----------------------------------------------
//求解非線性方程組,給定x和y,求解出t,u,v,w
void NonlinearEquationSolver(double x,double y,double* X)
{
	double x2[4];   //x2=[t u v w]'
	double del_x2[4];
	double** G=CreateMatrix(4,4);  //調用CreateMatrix函數,構建矩陣
	int i,j,k;
	for(i=0; i<4; i++)
	{
		del_x2[i]=0;
		x2[i]=1.0;  //給定初值
	}

	k=0;  //解非線性方程組的迭代次數
	do
	{
		k++;
		for(i=0; i<4; i++)
			x2[i] = x2[i]+del_x2[i];

		//計算Jacobi矩陣F',即G
		for(i=0; i<4; i++)
			for(j=0; j<4; j++)
				G[i][j]=1.0;
		G[0][0]=-0.5*sin(x2[0]);
		G[1][1]=0.5*cos(x2[1]);
		G[2][0]=0.5;
		G[2][2]=-sin(x2[2]);
		G[3][1]=0.5;
		G[3][3]=cos(x2[3]);
		
		//計算F,即-del_x2
		del_x2[0]=-(0.5*cos(x2[0])+x2[1]+x2[2]+x2[3]-x-2.67);
		del_x2[1]=-(x2[0]+0.5*sin(x2[1])+x2[2]+x2[3]-y-1.07);
		del_x2[2]=-(0.5*x2[0]+x2[1]+cos(x2[2])+x2[3]-x-3.74);
		del_x2[3]=-(x2[0]+0.5*x2[1]+x2[2]+sin(x2[3])-y-0.79);
		GaussElimination(G,4,del_x2);   //調用GaussElimination函數計算線性方程組F'*del_x=-F,解del_x即del_x2
	}while(fabs(InfiniteNorm(del_x2,4)/InfiniteNorm(x2,4))>PrecisionLevel);  //調用InfiniteNorm函數計算向量的無窮範數

	for(i=0;i<4;i++)
		X[i]=x2[i];
	DestroyMatrix(G,4,4);
}
//-----------------------------------------------
//求方陣的逆矩陣
bool InverseMatrix(double** A,int n)
{
	double* b;
	double** A1=CreateMatrix(n,n);
	double** A2=CreateMatrix(n,n);
	b=new double[n];
	int i,j,k;
	for(k=0; k<n; k++)
	{
		for(i=0; i<n; i++)
			for(j=0; j<n; j++)
				A1[i][j]=A[i][j];
		
		for(i=0; i<n; i++)
			if(i==k)
				b[i]=1;
			else
				b[i]=0;
			
		if(!GaussElimination(A1,n,b))
			return false;
		
		for(i=0; i<n; i++)
			A2[i][k]=b[i];
	}
	for(i=0; i<n; i++)
		for(j=0; j<n; j++)
			A[i][j]=A2[i][j];

	DestroyMatrix(A1,n,n);
	DestroyMatrix(A2,n,n);
	delete[]b;
	return true;
}
//-----------------------------------------------
//計算擬合曲面係數矩陣c_rs
void CoefficientMatrix(double* x,int m,double* y,int n,double** z,int k1,int k2,double** C)
{
	double** G=CreateMatrix(n,k2+1);
	double** B=CreateMatrix(m,k1+1);
	double** A1=CreateMatrix(k1+1,k1+1);
	double** A2=CreateMatrix(k2+1,k2+1);
	double** A3=CreateMatrix(k1+1,m);
	double** A4=CreateMatrix(n,k2+1);
	double* temp=new double[n];
	int i,j,r,s;

	for(i=0; i<n; i++)
		for(j=0; j<k2+1; j++)
			G[i][j]=pow(y[i],j);   //調用math庫函數pow計算y[i]的j次方,構建基函數組

	for(i=0; i<m; i++)
		for(j=0; j<k1+1; j++)
			B[i][j]=pow(x[i],j);

	//A1=B'*B
	for(i=0; i<k1+1; i++)
		for(j=0; j<k1+1; j++)
		{
			A1[i][j]=0;
			for(r=0; r<m; r++)
				A1[i][j]+=B[r][i]*B[r][j];
		}
	InverseMatrix(A1,k1+1);   //調用InverseMatrix函數,求矩陣的逆
	//A2=G'*G
	for(i=0; i<k2+1; i++)
		for(j=0; j<k2+1; j++)
		{
			A2[i][j]=0;
			for(r=0; r<n; r++)
				A2[i][j]+=G[r][i]*G[r][j];
		}
	InverseMatrix(A2,k2+1);
	//A3=A1*B'=(B'B)*B'
	for(i=0; i<k1+1; i++)
		for(j=0; j<m; j++)
		{
			A3[i][j]=0;
			for(r=0; r<k1+1; r++)
				A3[i][j]+=A1[i][r]*B[j][r];
		}
	//A4=G*A2=G*(G'*G)
	for(i=0; i<n; i++)
		for(j=0; j<k2+1; j++)
		{
			A4[i][j]=0;
			for(r=0; r<k2+1; r++)
				A4[i][j]+=G[i][r]*A2[r][j];
		}
	//C=A3*U*A4
	for(i=0; i<k1+1; i++)
		for(j=0; j<k2+1; j++)
		{
			C[i][j]=0;
			for(r=0; r<n; r++)
			{
				temp[r]=0;
				for(s=0; s<m; s++)
					temp[r]+=A3[i][s]*z[s][r];
				C[i][j]+=temp[r]*A4[r][j];
			}
		}

	delete[]temp;
	DestroyMatrix(G,n,k2+1);
	G=NULL;
	DestroyMatrix(B,m,k1+1);
	B=NULL;
	DestroyMatrix(A1,k1+1,k1+1);
	A1=NULL;
	DestroyMatrix(A2,k2+1,k2+1);
	A2=NULL;
	DestroyMatrix(A3,k1+1,m);
	A3=NULL;
	DestroyMatrix(A4,n,k2+1);
	A4=NULL;
}
//-----------------------------------------------
//計算p(x,y)值
double P_Value(double **C,int k,double x,double y)
{
	double sum=0.0;
	int r,s;
	for(r=0; r<=k; r++)
		for(s=0; s<=k; s++)
			sum+=C[r][s]*pow(x,r)*pow(y,s);
	return sum;
}
//-----------------------------------------------
//曲面擬合
double** SurfaceFitting(int& k)
{
	int i,j;
	double x1[11];
	double y1[21];
	double y[4];  //用於存儲非線性方程組的解y=[t u v w]'
	double** F=CreateMatrix(11,21);  //調用CreateMatrix函數創建矩陣
	//--------以下求解問題的第(1)問--------
	for(i=0; i<11; i++)  //計算xi,yj
		x1[i]=0.08*i;
	for(j=0; j<21; j++)
		y1[j]=0.5+0.05*j;
	printf("數表xi,yj,f(xi,yj)\n");
	for(i=0;i<11;i++)
	{
		for(j=0;j<21;j++)
		{
			NonlinearEquationSolver(x1[i],y1[j],y);  //調用NonlinearEquationSolver函數,求解非線性方程,返回解y,即求用於插值t和u
			F[i][j]=PiecewiseInterpolation(y[0],y[1]);   //調用PiecewiseInterpolation函數,進行分片二次插值求f(xi,yj)
			printf("%f %f %20.12e\n",x1[i],y1[j],F[i][j]);
		}
	}
	//--------以上求解問題的第(1)問--------
	printf("\n");
	//--------以下求解問題的第(2)問和第(3)問--------
	double sum;
	double** C;
	for(k=1; ;k++)
	{
		C=CreateMatrix(k+1,k+1);
		CoefficientMatrix(x1,11,y1,21,F,k,k,C);  //調用CoefficientMatrix函數,計算曲面擬合係數C_rs

		sum=0;     //對結果進行驗證
		for(i=0; i<11; i++)
			for(j=0; j<21; j++)   //調用P_Value函數,計算p(x,y),然後計算誤差平方和sigma
				sum+=(F[i][j]-P_Value(C,k,x1[i],y1[j]))*(F[i][j]-P_Value(C,k,x1[i],y1[j]));
		printf("k=%d sigma=%.12e\n",k,sum);   //顯示選擇過程中和達到精度要求時的k和sigma
		if(sum<=1.0e-7)
			break;
		if(k>7)
			break;
		DestroyMatrix(C,k+1,k+1);
		C=NULL;
	}
	//--------以上求解問題的第(2)問和第(3)問--------
	DestroyMatrix(F,11,21);
	return C;
}
//-----------------------------------------------
//主函數
void main()
{
	double **C;
	int i,j,k;
	double X[4];
	//初始化Z矩陣(二維數表)
	Z[0][0]=-0.5;  Z[0][1]=-0.34; Z[0][2]=0.14;  Z[0][3]=0.94;  Z[0][4]=2.06;  Z[0][5]=3.5;
	Z[1][0]=-0.42; Z[1][1]=-0.5;  Z[1][2]=-0.26; Z[1][3]=0.3;   Z[1][4]=1.18;  Z[1][5]=2.38;
	Z[2][0]=-0.18; Z[2][1]=-0.5;  Z[2][2]=-0.5;  Z[2][3]=-0.18; Z[2][4]=0.46;  Z[2][5]=1.42;
	Z[3][0]=0.22;  Z[3][1]=-0.34; Z[3][2]=-0.58; Z[3][3]=-0.5;  Z[3][4]=-0.1;  Z[3][5]=0.62;
	Z[4][0]=0.78;  Z[4][1]=-0.02; Z[4][2]=-0.5;  Z[4][3]=-0.66; Z[4][4]=-0.5;  Z[4][5]=-0.02;
	Z[5][0]=1.5;   Z[5][1]=0.46;  Z[5][2]=-0.26; Z[5][3]=-0.66; Z[5][4]=-0.74; Z[5][5]=-0.5;
	
	C=SurfaceFitting(k);   //調用SurfaceFitting函數求曲面擬合係數C_rs
	printf("\n係數矩陣C的計算結果:\n");
	for(i=0; i<=k; i++)
	{
		for(j=0;j<=k;j++)
			printf("%20.12e  ",C[i][j]);
		printf("\n");
	}
	//--------以下求解問題的第(4)問--------
	printf("\n檢驗p(x,y)逼近f(x,y)的效果:\n");
	printf("\n數表xi*,yj*,f(xi*,yj*),p(xi*,yj*):\n");
	for(i=1; i<=8; i++)
		for(j=1; j<=5; j++)
		{
			NonlinearEquationSolver(0.1*i,0.5+0.2*j,X);
			printf("%f %f %20.12e %20.12e\n",0.1*i,0.5+0.2*j,PiecewiseInterpolation(X[0],X[1]),P_Value(C,k,0.1*i,0.5+0.2*j));
		}
	//--------以上求解問題的第(4)問--------
	DestroyMatrix(C,k+1,k+1);

	system("pause");
}
//-----------------------------------------------

發佈了95 篇原創文章 · 獲贊 29 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章