高斯列主元消去法解线性方程组课程设计报告.docx
《高斯列主元消去法解线性方程组课程设计报告.docx》由会员分享,可在线阅读,更多相关《高斯列主元消去法解线性方程组课程设计报告.docx(29页珍藏版)》请在冰豆网上搜索。
高斯列主元消去法解线性方程组课程设计报告
一、引言
1.1编写目的
测试分析报告是把测试的结果写成文档,并对测试结果进行分析,为纠正软件的缺陷提供依据,也为软件验收和交付打下基础。
是软件开发的另一里程碑。
及时记录测试阶段的工作过程和工作成果,如实反映测试过程中所解决的各种问题,把集成测试和确认测试的结果以文件形式加以记载,使开发者能在第一时间对遇到的问题做迅速反应。
1.2背景
软件名称:
线性方程组求解
具体要求:
输入是N(N<256)元线性方程组Ax=B,输出是方程组的解,也可能无解或有多组解。
1.3算法说明
首先将线性方程组做成增广矩阵,对增广矩阵进行行变换。
对元素aii,在第i列中,第i行及以下的元素选取绝对值最大的元素,将该元素最大的行与第i行交换,然后采用高斯消元法将新得到的aii消去第i行以下的元素。
一次进行直到ann。
从而得到上三角矩阵。
再对得到的上三角矩阵进行回代操作,即可以得到方程组的解。
2、正文
(1)设计部分
该软件用于求解线性方程组的解。
执行过程:
(1)首先执行main()(主函数),输入待求解方程组的增广矩阵的行数,接着输入增广矩阵。
i.调用uptrbk(double*A,intN)(上三角变换函数),在此函数中又调用了两个函数:
FindMax(intp,intN,double*A)和ExchangeRow(intp,intj,double*A,intN)。
ii.FindMax()函数用于找出列向量中绝对值最大项的标号,ExchangeRow()用于交换两行。
iii.uptrbk()函数将矩阵行数N、增广矩阵指针A、行号p传给FindMax()函数,找出绝对值最大项的标号;
iiii.接着将绝对值最大项的标号传给ExchangeRow()函数,最终将绝对值最大的那行换到第一行。
(2)最后执行回代函数,求出方程组的解。
源代码:
#include
#include
#include
//在列向量中寻找绝对值最大的项,并返回该项的标号
intFindMax(intp,intN,double*A)
{
inti=0,j=0;
doublemax=0.0;
for(i=p;i{
if(fabs(A[i*(N+1)+p])>max)
{
j=i;
max=fabs(A[i*(N+1)+p]);
}
}
returnj;
}
//交换矩阵中的两行
voidExchangeRow(intp,intj,double*A,intN)
{
inti=0;
doubleC=0.0;
for(i=0;i{
C=A[p*(N+1)+i];
A[p*(N+1)+i]=A[j*(N+1)+i];
A[j*(N+1)+i]=C;
}
}
//上三角变换,A为增广矩阵的指针,N为矩阵的行数。
voiduptrbk(double*A,intN)
{
intp=0,k=0,q=0,j=0;
doublem=0.0;
for(p=0;p{
//找出该列最大项的标号
j=FindMax(p,N,A);
//交换p行和j行
ExchangeRow(p,j,A,N);
if(A[p*(N+1)+p]==0)
{
printf("矩阵是一个奇异矩阵,没有唯一解!
");
break;
}
//消去P元素以下的p列内容。
for(k=p+1;k{
m=A[k*(N+1)+p]/A[p*(N+1)+p];
for(q=p;qA[k*(N+1)+q]=A[k*(N+1)+q]-m*A[p*(N+1)+q];
}
}
printf("\n增广矩阵高斯列主元消去后的矩阵为:
\n");
for(j=0;j{
if(j%(N+1)==0)
printf("\n");
printf("%lf\t",A[j]);
}
}
//下面是回代函数
double*backsub(double*A,intN)
{
double*X=NULL,temp=0.0;
intk=0,i=0;
X=(double*)malloc(N*sizeof(double));X[N-1]=A[(N-1)*(N+1)+N]/A[(N-1)*(N+1)+N-1];
for(k=N-2;k>=0;k--)
{
temp=0.0;
for(i=k+1;itemp=temp+A[k*(N+1)+i]*X[i];
X[k]=(A[k*(N+1)+N]-temp)/A[k*(N+1)+k];
}
returnX;
}
main()
{
intN=0,i=0;
double*A=NULL,*X=NULL;
printf("\n请输入待求解方程组的增广矩阵的行数:
");
scanf("%d",&N);
if(N>256||N<=0)
{
printf("输入的数字不再范围之内!
!
!
");
printf("\n");
return0;}
else
{
A=(double*)calloc(N*(N+1),sizeof(double));
printf("请输入待求解方程组的增广矩阵(%d行%d列):
\n",N,N+1);
for(i=0;iscanf("%lf",&A[i]);
system("cls");
printf("方程的增广矩阵为:
\n");
for(i=0;i{
if(i%(N+1)==0)
printf("\n");
printf("%lf\t",A[i]);}
uptrbk(A,N);//上三角变换
X=backsub(A,N);//回代函数
printf("\n\n方程组的解为:
\n");
for(i=0;iprintf("X(%d)=%lf\n",i+1,X[i]);}
free(A);
free(X);
exit(0);
}
程序流程图如下:
(2)测试部分
2.测试过程及其结果
2.1测试方案
按测试技术分,本测试用到了白盒测试和黑盒测试;对于白盒测试技术,用到了路径覆盖法,上体包括语句覆盖,判定覆盖,条件覆盖,判定/条件覆盖,条件组合覆盖及物理路径覆盖法,对于黑盒测试技术,用决策表法;对于黑盒测试。
按测试方式分,本测试用到了静态测试和动态测试;
2.2单元测试
2.2.1黑盒测试
黑盒测试技术就是根据功能需求来设计测试用例,验证软件是否按照预期要求工作。
黑盒测试通常把程序看做一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下进行测试。
采用黑盒测试技术并不需要提供源代码,如果用户不能或者不愿意提供源代码,黑盒测试是可行的方法。
(1)采用边界条件法:
边界条件法是对等价类方法的扩张,因为长期的测试工作,发现大量错误是发生在边界条件上,而不是发生在内部。
因此,针对输入集合、输出集合和操作集合等价类的边界条件而设计出来的一些测试用例,更容易揭露软件中的缺陷。
//在列向量中寻找绝对值最大的项,并返回该项的标号
intFindMax(intp,intN,double*A)
{
inti=0,j=0;
doublemax=0.0;
for(i=p;i{
if(fabs(A[i*(N+1)+p])>max)
{
j=i;
max=fabs(A[i*(N+1)+p]);
}
}
returnj;
}
变量为N(行数),p(行号),且范围分别为0用例
N(行数)
p(行号)
预期输出
实际输出
1
0
0
输入的数字不在范围之内!
!
!
输入的数字不在范围之内!
!
!
2
1
0
j=0
j=0
3
125
124
j=50
j=50
4
256
255
j=45
j=45
5
257
256
输入的数字不在范围之内!
!
!
输入的数字不在范围之内!
!
!
(2)采用因果图法:
因果图法提供了一种把需求规格说明书转化为决策表的系统化方法。
等价类划分法和边界条件法着重考虑输入条件本身的属性,但未考虑输入条件之间的逻辑关系。
因果图法是一种帮助人们系统的选择一组高效的测试用例的方法,他适合检查程序输入条件的各种情况。
//交换矩阵中的两行
voidExchangeRow(intp,intj,double*A,intN)
{
inti=0;
doubleC=0.0;
for(i=0;i{
C=A[p*(N+1)+i];
A[p*(N+1)+i]=A[j*(N+1)+i];
A[j*(N+1)+i]=C;
}
}
原因
输入A
输入行数N
输入行号p
输入绝对值最大项标号j
结果
A[p]=A[j]
因果图:
输入A
输入行数N∧
交换A[p]=A[j]
输入行号p
输入绝对值最大项标号j
决策表:
1
2
3
4
输入
输入A
1
1
1
1
1
输入行数N
2
0
0
1
1
输入行号p
3
0
0
1
1
输入绝对值最大项标号j
4
0
0
1
1
中间节点
交换
11
0
1
0
1
输出
A[p]=A[j]
21
0
0
0
1
(3)采用因果图法:
//下面是回代函数
double*backsub(double*A,intN)
{
double*X=NULL,temp=0.0;
intk=0,i=0;
X=(double*)malloc(N*sizeof(double));X[N-1]=A[(N-1)*(N+1)+N]/A[(N-1)*(N+1)+N-1];
for(k=N-2;k>=0;k--)
{
temp=0.0;
for(i=k+1;itemp=temp+A[k*(N+1)+i]*X[i];
X[k]=(A[k*(N+1)+N]-temp)/A[k*(N+1)+k];
}
returnX;
}
原因
输入N
输入A
结果
返回X
因果图:
输入N
输入A返回X
决策表:
1
2
输入
输入A
1
1
1
输入N
2
0
1
输出
返回X
11
0
1
2.2.2白盒测试
白盒测试也称结构测试或逻辑驱动测试,通过了解软件系统的内部工作过程,设计测试用例来检测程序内部动作是否按照规格说明书规定的忠诚进行,按照程序内部的结构测试程序,检查程序中的每条通路是否都能按照预定要求正确工作。
2.2.2.1基于条件路径覆盖
条件路径覆盖对于每个判定中所包含的若干个条件,应设计足够多的测试用例,使得判定中的每个条件都至少取一次“真值”和“假值”。
(1)intFindMax(intp,intN,double*A)该函数用于找出列向量中绝对值最大项的标号。
s
a
b
YN
c
YN
d
e
f
g
测试用例
测试数据
预期结果
测试路径
CASE1
N=1,p=0
返回绝对值最大项下标
sabcdebfg
CASE2
N=3,p=1
返回绝对值最大项下标
sabcdebcefg
(2)double*backsub(double*A,intN)该函数为回代函数。
s
a
b
c
Y
d
N
e
Y
fN
g
h
j
k
l
测试用例
测试数据
预期结果
测试路径
CASE1
N=1
进行上三角变换
sabckl
CASE2
N=2
进行上三角变换
sabcdefgehjkl
(3)voidExchangeRow(intp,intj,double*A,intN)该函数用于交换两行。
s
a
b
YN
c
d
e
测试用例
测试数据
预期结果
测试路径
CASE1
N=1
交换两行
sabcdbcdbe
CASE2
N=2
交换两行
sabcdbcdbcdbe
2.3集成测试:
集成测试就是策略就是在分析测试对象的基础上,描述软件模块集成的方式、方法。
集成测试的基本策略较多。
如大爆炸集成、自底向上集成、自顶向下集成、三明治集成、协议集成和高频集成等方法。
本软件系统比较小,而且它的每个模块都通过了充分的单元测试,所以本软件系统的集成测试策略采用大爆炸集成。
测试方法采用自动化测试技术。
2.3.1测试软件与测试过程
测试过程中使用的测试软件是C++Test,整个测试过程分为动态测试、静态测试和源代码测试。
2.3.1.1动态测试:
voiduptrbk(double*,int):
该函数实现增广矩阵的上三角变换
问题分析:
(1)
问题出现位置:
57:
printf("\n增广矩阵高斯列主元消去后的矩阵为:
\n");
58:
for(j=0;j59:
{
60:
if(j%(N+1)==0)
61:
printf("\n");
62:
>>>printf("%lf\t",A[j]);
63:
}
64:
}
65:
//下面是回代函数
66:
double*backsub(double*A,intN)
67:
{
在此段代码62行处可能发生访问越界。
(2)
问题出现位置:
7:
{
8:
inti=0,j=0;
9:
doublemax=0.0;
10:
for(i=p;i11:
{
12:
>>>if(fabs(A[i*(N+1)+p])>max)//fabs()求浮点数的绝对值
13:
{
14:
j=i;
15:
max=fabs(A[i*(N+1)+p]);
16:
}
17:
}
在此段代码12行处可能出现数组越界。
(3)
问题出现位置:
7:
{
8:
inti=0,j=0;
9:
doublemax=0.0;
10:
for(i=p;i11:
{
12:
>>>if(fabs(A[i*(N+1)+p])>max)//fabs()求浮点数的绝对值
13:
{
14:
j=i;
15:
max=fabs(A[i*(N+1)+p]);
16:
}
17:
}
在此段代码12行处可能出现数组越界。
覆盖率:
2.3.1.2静态测试:
问题分析:
(1)
问题出现位置:
38:
{
39:
//找出该列最大项的标号
40:
j=FindMax(p,N,A);
41:
//交换p行和j行
42:
ExchangeRow(p,j,A,N);
43:
>>>if(A[p*(N+1)+p]==0)
44:
{
45:
printf("矩阵是一个奇异矩阵,没有唯一解!
");
46:
break;
47:
}
48:
//消去P元素以下的p列内容。
在此段代码43行处发生访问越界,导致访问冲突。
(2)
问题出现位置:
324:
_CRTIMPchar*__cdeclgets(char*);
325:
_CRTIMPint__cdecl_getw(FILE*);
326:
_CRTIMPvoid__cdeclperror(constchar*);
327:
_CRTIMPint__cdecl_pclose(FILE*);
328:
_CRTIMPFILE*__cdecl_popen(constchar*,constchar*);
329:
>>>_CRTIMPint__cdeclprintf(constchar*,...);
330:
_CRTIMPint__cdeclputc(int,FILE*);
331:
_CRTIMPint__cdeclputchar(int);
332:
_CRTIMPint__cdeclputs(constchar*);
333:
_CRTIMPint__cdecl_putw(int,FILE*);
334:
_CRTIMPint__cdeclremove(constchar*);
在此段代码57行处调用printf()函数时传递参数出现问题。
2.3.1.3编码规则测试:
(1)
问题出现位置:
55:
56:
}
57:
printf("\n增广矩阵高斯列主元消去后的矩阵为:
\n");
58:
for(j=0;j59:
{
60:
>>>if(j%(N+1)==0)
61:
printf("\n");
62:
printf("%lf\t",A[j]);
63:
}
64:
}
65:
//下面是回代函数
C++Test编码规范规定,条件语句的语句块要用大括号括起来,而程序中没有。
(2)
问题出现位置:
98:
A=(double*)calloc(N*(N+1),sizeof(double));
99:
printf("请输入待求解方程组的增广矩阵(%d行%d列):
\n",N,N+1);
100:
101:
for(i=0;i102:
scanf("%lf",&A[i]);
103:
>>>system("cls");//清除屏幕上所有显示
104:
105:
printf("方程的增广矩阵为:
\n");
106:
for(i=0;i107:
{
108:
if(i%(N+1)==0)
C++Test编码规范规定,程序中应避免使用shell脚本函数,而程序在103行处调用了脚本函数。
(3)
问题出现位置:
78:
X[k]=(A[k*(N+1)+N]-temp)/A[k*(N+1)+k];
79:
}
80:
returnX;
81:
}
82:
83:
>>>main()
84:
{
85:
intN=0,i=0;
86:
double*A=NULL,*X=NULL;
87:
printf("\n请输入待求解方程组的增广矩阵的行数:
");
88:
scanf("%d",&N);
C++Test编码规范规定,函数应明确返回类型,而此函数没有明确表示。
(4)
问题出现位置:
85:
intN=0,i=0;
86:
double*A=NULL,*X=NULL;
87:
printf("\n请输入待求解方程组的增广矩阵的行数:
");
88:
scanf("%d",&N);
89:
90:
>>>if(N>256||N<=0)
91:
{
92:
printf("请输入0-256的数字!
!
!
");
93:
printf("\n");
94:
return0;
95:
}
C++Test编码规范规定,有条件的表达逻辑部分应归入括号的一个条件表达式的逻辑部分,即使逻辑上没有要求。
(5)
问题出现位置:
5:
//在列向量中寻找绝对值最大的项,并返回该项的标号
6:
intFindMax(intp,intN,double*A)
7:
{
8:
inti=0,j=0;
9:
doublemax=0.0;
10:
>>>for(i=p;i11:
{
12:
if(fabs(A[i*(N+1)+p])>max)//fabs()求浮点数的绝对值
13:
{
14:
j=i;
15:
max=fabs(A[i*(N+1)+p]);
C++Test编码规范规定,分号与下一条语句之间应加一个空格,而此程序中没有。
(6)
问题出现位置:
83:
main()
84:
{
85:
intN=0,i=0;
86:
double*A=NULL,*X=NULL;
87:
printf("\n请输入待求解方程组的增广矩阵的行数:
");
88:
>>>scanf("%d",&N);
89:
90:
if(N>256||N<=0)
91:
{
92:
printf("请输入0-256的数字!
!
!
");
93:
printf("\n");
C++Test编码规范规定,经过’%’的位置编号:
1应该是数字格式的,且描述变量的大小。
2.4系统测试:
系统测试是通过与系统规格做比较,发现软件与系统需求规格不相符合或与之矛盾的地方。
它将软件作为整个基于计算机系统的一个元素,与计算机硬件、外设、某系支持软件、数据和人员等其他系统元素结合起来,在实际运行(使用)环境下,对计算机系统进行测试。
对所编写的高斯列主元程序进行编译和链接,然后执行得如下所示的窗口,我们按命令输入增广矩阵的行数为4,输入4行5列的增广矩阵:
按回车键后,程序执行得如下所示的结果:
实例
增广矩阵行数
增广矩阵
输出结果
1
2
135
257
2
3
2312456
34452110
23811
三、结论
3.1总结
采用高斯列主元消去法解线性方程组得到的结果和实际的计算结果是一致的,高斯列主元消去法比较简单,在提高近似值解的精度上是非常起作用的,而且又具有计算量不大、算法组织容易,且对于有唯一解的线性方程组都可以计算,要求的条件比较低等等优点。
不过,由于消去的循环次数比较多,当要解决比较大的线性方程组时计算就比较慢