求积分的两点高斯公式

求积分的两点高斯公式,第1张

高斯求积公式是变步长数值积分的一种,基本形式是计算[-1,1]上的定积分。下面简单说明一下思想(仅仅是说明,而非证明): 假设现在要求f(x)在[-1,1]上的积分值,只允许计算一次f(x)的值,你会怎么做呢?

显然我们会选取一点x0,计算出f(x0),然后用A=f(x0)2作为近似值。现在问题是怎样选取x0,使得结果尽可能精确呢?

直觉告诉我们选取区间中点最合适,这也就是所谓的中点公式,也就是1点高斯求积公式。

如果选取个点作为计算节点,同样可以按公式:A=k1f(x1)+k2f(x2)++knf(xn)来计算近似值,关键就是如何确定节点xi和系数ki(i=1,2,3,,n) 理论证明对于n个节点的上述求积公式,最高有2n-1次的代数精度,高斯公式就是使得上述公式具有2n-1次代数精度的积分公式。至于如何确定公式中的节点和系数,最常见的是利用勒让德多项式,具体的这里不方便说,你查查相关资料吧。

这里向你推荐一下克鲁特算法(其实就是对高斯列主元消元法进行优化,使之更适合于计算机编程),首先将矩阵A进行LU分解(将系数矩阵分解成一个上三角矩阵和一个下三角矩阵),分解的过程中用到了隐式的主元寻找法,同时利用克鲁特算法可以将两个nn矩阵压缩到一个nn矩阵中,大大节省了存储空间提高了计算速度。

方程可化为LUx=B,令Ux=y --->Ly=B

然后利用回代先求y,再利用y求x

因为该方法在求解过程中不涉及增广矩阵所以矩阵B几乎不参与什么运算,所以它的计算速度应该能够达到高斯列主元消元法的三倍,但原理与其基本一致。

而且我在程序中使用了动态数组方便你今后进行扩展。

以下程序按照《矩阵论第二版》和《C语言数值计算法方法大全》编写,LU分解部分程序主要参考了《C语言数值计算法方法大全》第二章的程序

如果你需要详细的理论讲解我可以将这两本书和源程序发给你,上面的论述相当详细足够你答辩用的了,我的邮箱hu_hu605@163com

计算结果:

A矩阵:

2 2 5

3 4 7

1 3 3

B矩阵:

5

6

5

解矩阵:

x 1=-7

x 2=0333333

x 3=366667

Press any key to continue

#include <cmath>

#include <iostream>

#include <iomanip>

#include <cstdlib>

#include <functional>

#include <vector>

#include <algorithm>

using namespace std;

#define TINY 10e-20 //A small number

#define N 3

void ludcmp(vector<vector<float> > &a, int n, vector<int> &indx, float &d);//对矩阵进行LU分解

void lubksb(vector<vector<float> > &a, int n, vector<int> &indx, vector<float> &b);//对矩阵进行前向和后向回代

void root(vector<vector<float> > &x,vector<float> &col);//解方程结果保存在y中

void iniv(vector<vector<float> > &x,vector<float> line,int n);//对二维动态数组进行初始化

void main()

{

int i,j,n=N;//输入矩阵的维数

float A[N][N]={{2,2,5},{3,4,7},{1,3,3}};//左边A矩阵

float B[N]={5,6,5};//右边B矩阵

vector<vector<float> > x;//建立动态二维数组存放A,保证你的程序进行扩展时只改A,B,N

vector<float> line;

vector<float> y(n);//建立动态数组存放B

iniv(x,line,n);

yclear();

for(i=0;i<n;i++)//将A赋给x,B赋给y

{

ypush_back(B[i]);

for(j=0;j<n;j++)

{

x[i]push_back(A[i][j]);

}

}

cout<<"A矩阵:"<<endl;

for(i=0;i<n;i++)

{

for(j=0;j<n;j++)

{

cout<<setw(2)<<setiosflags(ios::left)<<setw(2)<<x[i][j]<<" ";

}

cout<<endl;

}

cout<<"B矩阵:"<<endl;

for(i=0;i<n;i++)

{

cout<<setw(2)<<setiosflags(ios::left)<<setw(2)<<y[i]<<endl;

}

root(x,y);//求根

cout<<"解矩阵:"<<endl;

for(i=0;i<n;i++)

{

cout<<setw(2)<<setiosflags(ios::left)<<"x"<<i+1<<"="<<y[i]<<endl;

}

cout<<endl;

}

void root(vector<vector<float> > &x,vector<float> &col)

{

int n=xsize(),i=0,j=0;

vector<int> index(n);//用于记录寻找主元素过程中对矩阵的初等变换

indexclear();

float m=10;//记录变换方式,此程序中无用

ludcmp(x,n,index,m);//进行LU分解

lubksb(x,n,index,col);//根据分解结果进行回带

}

//以下程序按照《矩阵论第二版》和《C语言数值计算法方法大全》编写,LU分解部分程序主要参考了《C语言数值计算法方法大全》第二章的程序

//如果你需要详细的理论讲解我可以将这两本书和源程序发给你,我的邮箱hu_hu605@163com

void ludcmp(vector<vector<float> > &a, int n, vector<int> &indx, float &d)

{

int i,imax,j,k;

float big=0,dum=0,sum=0,temp=0;

vector<float> vv(n);

vvclear();

d=10;

for (i=0;i<n;i++)

{

big=00;

for (j=0;j<n;j++)

if ((temp=fabs(a[i][j])) > big)

big=temp;

vv[i]=10/big;

}

for (j=0;j<n;j++)

{

for (i=0;i<j;i++)

{

sum=a[i][j];

for (k=0;k<i;k++)

sum -= a[i][k]a[k][j];

a[i][j]=sum;

}

big=00;

for (i=j;i<n;i++)

{

sum=a[i][j];

for (k=0;k<j;k++)

sum -= a[i][k]a[k][j];

a[i][j]=sum;

if ( (dum=vv[i]fabs(sum)) >= big)

{

big=dum;

imax=i;

}

}

if (j != imax)

{

for (k=0;k<n;k++)

{

dum=a[imax][k];

a[imax][k]=a[j][k];

a[j][k]=dum;

}

d = -(d);

vv[imax]=vv[j];

}

indx[j]=imax;

if (a[j][j] == 00)

a[j][j]=TINY;

if (j != n)

{

dum=10/(a[j][j]);

for (i=j+1;i<n;i++)

a[i][j] = dum;

}

}

}

void lubksb(vector<vector<float> > &a, int n, vector<int> &indx, vector<float> &b)

{

int i,ii=0,ip,j;

float sum;

for(i=0;i<n;i++)//按LU分解时寻找主元所进行的初等变换进行反边变换。

{

ip=indx[i];

sum=b[ip];

b[ip]=b[i];

b[i]=sum;

}

sum=0;

for (i=1;i<n;i++)

{

sum=0;

for(j=0;j<i;j++)

{

sum+=a[i][j]b[j];

}

b[i]=b[i]-sum;

}

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];

}

}

void iniv(vector<vector<float> > &x,vector<float> line,int n)

{

int i,j;

for(i=0;i<n;i++)

{

xpush_back(line);

for(j=0;j<n;j++)

{

x[i]clear();

}

}

}

void gaussj(double a[], int n, double b[])

{

int i,j,k,l,ll,irow,icol;

double big,pivinv,dum;

int ipiv[50], indxr[50], indxc[50];

for (j=0;j<=n-1;j++)

{

ipiv[j]=0;

}

for (i=0;i<=n-1;i++)

{

big=00;

for (j=0;j<=n-1;j++)

{

if(ipiv[j]!=1)

{

for(k=0;k<=n-1;k++)

{

if(ipiv[k]==0)

{

if(fabs(a[jn+k])>=big)

{

big=fabs(a[jn+k]);

irow=j;

icol=k;

}

else if(ipiv[k]>1)

{

cout<<"singular matrix";

}

}

}

}

}

ipiv[icol]=ipiv[icol]+1;

if(irow!=icol)

{

for(l=0;l<=n-1;l++)

{

dum=(a[irown+l]);

a[irown+l]=a[icoln+l];

a[icoln+l]=dum;

}

dum=b[irow];

b[irow]=b[icol];

b[icol]=dum;

}

indxr[i]=irow;

indxc[i]=icol;

if(a[icoln+icol]==00)

{

cout<< "singular matrix";

}

pivinv=10/(a[icoln+icol]);

a[icoln+icol]=10;

for(l=0;l<=n-1;l++)

{

a[icoln+l]=a[icoln+l]pivinv;

}

b[icol]=b[icol]pivinv;

for(ll=0;ll<=n-1;ll++)

{

if(ll!=icol)

{

dum=a[lln+icol];

a[lln+icol]=00;

for(l=0;l<=n-1;l++)

{

a[lln+l]=a[lln+l]-a[icoln+l]dum;

}

b[ll]=b[ll]-b[icol]dum;

}

}

}

for(l=n-1;l<=0;l--)

{

if(indxr[l]!=indxc[l])

{

for(k=0;k<=n-1;k++)

{

dum=a[kn+indxr[l]];

a[kn+indxr[l]]=a[kn+indxc[l]];

a[kn+indxr[l]]=dum;

}

}

}

}

高斯求积公式是变步长数值积分的一种,基本形式是计算[-1,1]上的定积分。

假设现在要求f(x)在[-1,1]上的积分值,只允许计算一次f(x)的值,会选取一点x0,计算出f(x0),用A=f(x0)2作为近似值。现在问题是怎样选取x0,使得结果尽可能精确,直觉告诉我们选取区间中点最合适,这也就是所谓的中点公式,也就是1点高斯求积公式。

含义

由于磁力线总是闭合曲线,因此任何一条进入一个闭合曲面的磁力线必定会从曲面内部出来,否则这条磁力线就不会闭合起来了。如果对于一个闭合曲面,定义向外为正法线的指向,则进入曲面的磁通量为负,出来的磁通量为正,那么就可以得到通过一个闭合曲面的总磁通量为0。这个规律类似于电场中的高斯定理,因此也称为高斯定理。

百度百科-高斯公式

% 高斯-勒让德数值积分

fun=@(x)sin(x)x^3; % fun:积分表达式

% a,b:积分上下限

a = 0;

b = pi;

tol=1e-8; % tol:积分精度,默认1e-6

% 计算求积节点

syms x

p=sym2poly(diff((x^2-1)^(n+1),n+1))/(2^nfactorial(n));

tk=roots(p); % 求积节点

% 计算求积系数

Ak=zeros(n+1,1);

for i=1:n+1

xkt=tk;

xkt(i)=[];

pn=poly(xkt);

fp=@(x)polyval(pn,x)/polyval(pn,tk(i));

Ak(i)=quadl(fp,-1,1,tol); % 求积系数

end

% 积分变量代换,将[a,b]变换到[-1,1]

xk=(b-a)/2tk+(b+a)/2;

% 检验积分函数fun有效性

fun=fcnchk(fun,'vectorize');

% 计算变量代换之后积分函数的值

fx=fun(xk)(b-a)/2;

% 计算积分值

ql=sum(Akfx)

quadl(fun,0,pi) % 调用MATLAB内部积分函数检验

//TurboC 20太落后了,建议使用VC++60。

#include"stdioh"

#include"mathh"

//最大49阶

#define N 50

void Gauss(float U[N][N],int n);

void main()

{

int n,i,j;

float U[N][N];

printf("------------特殊说明---------------\n");

printf("当输出的数据含有<-1#IND>时,表示在计算过程中数据已经出现溢出!\n");

printf("-----------------------------------\n");

printf("输入对应方程的阶数:");

scanf("%d",&n);

for(i=0;i<N;i++)

for(j=0;j<N;j++)

U[i][j]=0;

printf("输入方程组的增广矩阵:\n");

for(i=0;i<n;i++)

for(j=0;j<=n;j++)

scanf("%f",&U[i][j]);

Gauss(U,n);

}

//高斯选列主元消去法

void Gauss(float U[N][N],int n)

{

int i,j,m,row;

float max,t,sum;

float result[50];

for(m=0;m<n-1;m++)

{

//选取主元

max=U[m][m];

for(i=m;i<n;i++)

{

if(fabs(max)<fabs(U[i][m]))

{

max=U[i][m];

row=i;

}

}

if(fabs(max)<001)

{

printf("主元接近于零,方法失效!\n");

return;

}

else

{

if(max!=U[m][m])

{

for(j=m;j<=n;j++)

{

t=U[m][j];

U[m][j]=U[row][j];

U[row][j]=t;

}

}

}

//消元

for(i=m+1;i<n;i++)

{

float t1,t2;

t1=U[i][m];

t2=U[m][m];

U[i][m]=0;

for(j=m+1;j<=n;j++)

U[i][j]=U[i][j]t2-U[m][j]t1;

}

}

//回代求解

for(i=n-1;i>=0;i--)

{

if(i==n-1) result[i]=U[i][i+1]/U[i][i];

else

{

sum=0;

for(j=i+1;j<n;j++)

sum=U[i][j]result[j]+sum;

result[i]=(U[i][n]-sum)/U[i][i];

}

}

//输出根

printf("高斯选列主元消去法求得的解为:\n");

for(i=0;i<n;i++)

printf("%33f ",result[i]);

printf("\n");

}

我有VB的,自己很多年前写的,一直用,但是正算->反算->正算后,Y坐标与原来的差了05-07mm,不知道怎么回事,这两年工作忙也没有时间再深究,但是这样的计算精度做控制足够了,如果楼主或是者是哪位同仁见此贴能顺便把这个问题解决了,咱们就一起进步了!代码如下:

'高斯坐标正算

Private Sub DadiZs()

Dim t As Double, Itp As Double, X0 As Double, N As Double, L0 As Double

Dim V As Double, ll As Double, W As Double, M As Double

Lat = Radian(Lat)

Lon = Radian(Lon)

L0 = Radian(Lo)

If Tq = 0 Then

a = 6378245 '54椭球参数

b = 635686301877305

ep = 0006693421622966

ep1 = 0006738525414683

f = (a - b) / a

c = a ^ 2 / b

d = b ^ 2 / a

X0 = 1111348611 (Lat 180# / Pi) - (320057799 Sin(Lat) + 1339238 (Sin(Lat)) ^ 3 + 06973 (Sin(Lat)) ^ 5 + 00039 (Sin(Lat)) ^ 7) Cos(Lat)

'X0 = 1111348611 (Lat 180# / Pi) - (320057798 Sin(Lat) + 1339238 (Sin(Lat)) ^ 3 + 06972 (Sin(Lat)) ^ 5 + 00039 (Sin(Lat)) ^ 7) Cos(Lat)

Else

a = 6378140 '75椭球参数

b = 635675528815753

ep = 0006694384999588

ep1 = 0006739501819473

f = (a - b) / a

c = a ^ 2 / b

d = b ^ 2 / a

X0 = 1111330047 (Lat 180 / Pi) - (320098575 Sin(Lat) + 1339602 (Sin(Lat)) ^ 3 + 06976 (Sin(Lat)) ^ 5 + 00039 (Sin(Lat)) ^ 7) Cos(Lat)

End If

ll = Lon - L0

t = Tan(Lat)

Itp = ep1 Cos(Lat) ^ 2

W = Sqr(1 - ep Sin(Lat) ^ 2)

V = Sqr(1 + ep1 Cos(Lat) ^ 2)

M = c / V ^ 3

N = a / W

'x = X0 + N t (Cos(Lat)) ^ 2 ll ^ 2 / 2 + N t (5 - t t + 9 Itp + 4 Itp Itp) (Cos(Lat)) ^ 4 ll ^ 4 / 24 + N t (61 - 58 t ^ 2 + t ^ 4 + 270 Itp - 330 t ^ 2 Itp) (Cos(Lat)) ^ 6 ll ^ 6 / 720 + N t (1385 - 3111 t ^ 2 + 543 t ^ 4 - t ^ 6) Cos(Lat) ^ 8 ll ^ 8 / 40320

x = X0 + N t (Cos(Lat)) ^ 2 ll ^ 2 / 2 + N t (5 - t t + 9 Itp ^ 2 + 4 Itp ^ 4) (Cos(Lat)) ^ 4 ll ^ 4 / 24 + N t (61 - 58 t ^ 2 + t ^ 4 + 270 Itp ^ 2 - 330 t ^ 2 Itp ^ 2) (Cos(Lat)) ^ 6 ll ^ 6 / 720 + N t (1385 - 3111 t ^ 2 + 543 t ^ 4 - t ^ 6) Cos(Lat) ^ 8 ll ^ 8 / 40320

y = N Cos(Lat) ll + N (1 - t t + Itp) (Cos(Lat)) ^ 3 ll ^ 3 / 6 + N (5 - 18 t t + t ^ 4 + 14 Itp - 58 Itp t t) (Cos(Lat)) ^ 5 ll ^ 5 / 120 + N (61 - 479 t ^ 2 + 179 t ^ 4 - t ^ 6) Cos(Lat) ^ 7 ll ^ 7 / 5040

r = Sin(Lat) ll + Sin(Lat) (Cos(Lat)) ^ 2 ll ^ 3 (1 + 3 Itp + 2 Itp ^ 2) / 3 + Sin(Lat) (Cos(Lat)) ^ 4 ll ^ 5 (2 - t t) / 15

r = Degree(r)

y = y + 500000#

End Sub

'高斯反算

Private Sub DadiFs()

Dim t As Double, Itp As Double, X0 As Double, Bf As Double, N As Double

Dim v As Double, ll As Double, W As Double, M As Double, L0 As Double

L0 = Radian(Lo)

X0 = x 0000001

y = y - 500000#

If Tq = 0 Then

a = 6378245 '54椭球参数

b = 635686301877305

ep = 0006693421622966

ep1 = 0006738525414683

f = (a - b) / a

c = a ^ 2 / b

d = b ^ 2 / a

If X0 < 3 Then

Bf = 904353301294 X0 - 000000049604 X0 ^ 2 - 000075310733 X0 ^ 3 - 000000084307 X0 ^ 4 - 000000426055 X0 ^ 5 - 000000010148 X0 ^ 6

ElseIf X0 < 6 Then

Bf = 2711115372595 + 902468257083 (X0 - 3) - 000579740442 (X0 - 3) ^ 2 - 000043532572 (X0 - 3) ^ 3 + 000004857285 (X0 - 3) ^ 4 + 000000215727 (X0 - 3) ^ 5 - 000000019399 (X0 - 3) ^ 6

End If

Else

a = 6378140 '75椭球参数

b = 635675528815753

ep = 0006694384999588

ep1 = 0006739501819473

f = (a - b) / a

c = a ^ 2 / b

d = b ^ 2 / a

If X0 < 3 Then

Bf = 904369066313 X0 - 000000049618 X0 ^ 2 - 000075325505 X0 ^ 3 - 00000008433 X0 ^ 4 - 000000426157 X0 ^ 5 - 00000001015 X0 ^ 6

ElseIf X0 < 6 Then

Bf = 2711162289465 + 902483657729 (X0 - 3) - 000579850656 (X0 - 3) ^ 2 - 000043540029 (X0 - 3) ^ 3 + 000004858357 (X0 - 3) ^ 4 + 000000215769 (X0 - 3) ^ 5 - 000000019404 (X0 - 3) ^ 6

End If

End If

Bf = Bf Pi / 180#

t = Tan(Bf)

Itp = ep1 Cos(Bf) ^ 2

W = Sqr(1 - ep Sin(Bf) ^ 2)

v = Sqr(1 + ep1 Cos(Bf) ^ 2)

M = c / v ^ 3

N = a / W

Lat = Bf - 05 v ^ 2 t ((y / N) ^ 2 - (5 + 3 t t + Itp - 9 Itp t t) (y / N) ^ 4 / 12 + (61 + 90 t t + 45 t ^ 4) (y / N) ^ 6 / 360)

ll = ((y / N) - (1 + 2 t t + Itp) (y / N) ^ 3 / 6 + (5 + 28 t t + 24 t ^ 4 + 6 Itp + 8 Itp t t) (y / N) ^ 5 / 120) / Cos(Bf)

r = y t / N - y ^ 3 t (1 + t t - Itp) / (3 N ^ 3) + y ^ 5 t (2 + 5 t t + 3 t ^ 4) / (15 N ^ 5)

Lat = Degree(Lat)

Lon = Degree(L0 + ll)

r = Degree(r)

End Sub

有了正反算,换带也就完成了!

用到的子程序:

Public Const Pi = 314159265358979, p = 206264806

Public Cktq As String

'角度化弧度

Public Function Radian(a As Double) As Double

Dim Ro As Double

Dim c As Double

Dim Fs As Double

Dim Ib As Integer

Dim Ic As Integer

If a < 0 Then a = -a: t = 1

Ro = Pi / 180#

Ib = Int(a)

c = (a - Ib) 100#

Ic = Int(c + 0000000000001)

Fs = (c - Ic) 100#

If t = 1 Then Radian = -(Ib + Ic / 60# + Fs / 3600#) Ro Else Radian = (Ib + Ic / 60# + Fs / 3600#) Ro

End Function

'弧度化角度

Public Function Degree(a As Double) As Double

Dim Bo As Double

Dim Fs As Double

Dim Im As Integer

Dim Id As Integer

If a < 0 Then a = -a: t = 1

Bo = a

Call DMS(Bo, Id, Im, Fs)

If t = 1 Then Degree = -(Id + Im / 100# + Fs / 10000#) Else Degree = Id + Im / 100# + Fs / 10000#

End Function

Public Sub DMS(a As Double, Id As Integer, Im As Integer, Fs As Double)

Dim Bo As Double

Dim c As Double

c = a

c = 180# / Pi c

Id = Int(c)

Bo = (c - Id) 60

Im = Int(Bo)

Fs = (Bo - Im) 60

End Sub

'取位计算

Public Function Qw(a As Double, Ws As Integer) As Double

Qw = Int(a 10 ^ Ws + 05) / 10 ^ Ws

End Function

以上就是关于求积分的两点高斯公式全部的内容,包括:求积分的两点高斯公式、求C语言课程设计:用高斯列主元消元法解线性方程组、【编程求助】用c语言或者c++编程,实现用高斯消元法求解线性方程组Ax=b。等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/9537893.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存