求解线性方程组
求解线性方程组
摘要:自从1946年世界上第一台计算机诞生,计算机在我们的生活作用也越来越重要,它
多样化的功能与日趋简便的操作使得利用计算机求解算数问题成为一种趋势。线性方程组求
解计算量大过程复杂,所以我们小组通过C++软件编写求解线性方程组程序。该程序功能强
大,具有求解线性方程组、三角函数、对数函数、指数函数的功能。而且程序加了新的元素,全数字化控制,使用简单方便。
关键词:高斯消元法;C语言;线性方程组;常用函数求解。
1 绪论
1.1 研究背景
随着人们对计算类软件的需求,求解线性方程组成为常见的应用。线性方程组求解未知
数多,方程复杂,人工计算较难实现。为解决这类问题,本小组通过微软公司的VC6.0软
件设计一款用C语言求解线性方程组的软件,并能进行常用函数的辅助运算。
1.2主要工作
一个软件开发需要大量人力、物力支持,还需要合理有序的工作分配,明确一个软件必
须要有哪些功能,可以添加哪些功能。线性方程组求解程序有求解功能和辅助功能。因此主
要工作是深刻理解高斯消元法原理和初等矩阵,掌握矩阵变换步骤,常用函数的原理;再利
用C语言编写一系列代码,解决方程组求解问题。
1.3本文结构
本文第1部分绪论主要说明了本文的研究背景、主要工作和实现方法。第2部分相关知
识介绍。第3部分系统设计,阐述了需求分析、系统模型设计和系统工作流程设计。第4
部分系统实现介绍了系统各个功能模块,并描述了系统功能图。第5部分软件的调试和验证,进行截图。第六部分总结和心的体会。
2 相关知识
以下就线形方程求解过程中和其它的相关知识进行间要介绍。
2.1高斯消元法原理
2.1.1初等矩阵
(1)单位矩阵第i,j两行(列)互换得到的方阵为Pij。将矩阵B的第i,j两行(列)互换
所得矩阵B1,即有PijB=B1
(2)单位矩阵第i行(列)乘以常数k得到初等方阵Di(k),将矩阵B的第i行(列)乘
以k得到矩阵B2,即有B2=Di(k)B。
(3)将单位矩阵的第j行(列)的k倍加到第i行(列)得到初等方阵Tij(k),矩阵B
的第j行(列)的k倍加到第i行(列)得到矩阵B3,即有B3=Tij(k)B。矩阵B的第i列的k
倍加到第j列得到矩阵B3,即有B3=BTij(k)。
2.1.2高斯消元法
消元法可用来找出下列方程组的解或其解的限制:
2abx8...X()
-3a - b 2c -11 .(.Y. )
2ab2c3...(Z)
这个算法的原理是:
首先,要将X 以下的等式中的a 消除,然后再将Y 以下的等式中的b 消除。这样可
使整个方程组变成一个三角形似的格式。之后再将已得出的答案一个个地代入已被简化的等
式中的未知数中,就可求出其余的答案了。
在刚才的例子中,将3/2 X和Y相加,就可以将Y 中的a 消除了。然后再将X 和Z
相加,就可以将Z 中的a消除。
可以这样写:Y + 3/2 X→ Y ;Z+ X → Z
结果就是:2a + b - c = 8;1/2 b + 1/2c = 1 ;2b + c = 5
现在将 − 4Y 和Z 相加,就可将Z 中的b 消除:Z + (-4Y) → Z
其结果是:
2abc8
1/2b 1/2c 1
-c 1
这样就完成了整个算法的初步,一个三角形的格式(指:变量的格式而言,上例中的变量各
为(3,2,1个)出现了。
第二步,就是由尾至头地将已知的答案代入其他等式中的未知数。第一个答案就是:
c -1
然后就可以将c 代入Y 中,立即就可得出第二个答案:
b 3
之后,将c 和b 代入X 之中,最后一个答案就出来了:
a 2
3 软件设计
3.1需求分析
经过对程序设计题目的分析可知,整个程序的设计实现大致分为三个模块,分别是:输
入方程组,计算方程组,继续运算/退出。要求以菜单的形式调用各功能函数:程序可读性
强,界面新意,输出形式美观。
3.2软件流程设计
打开线性方程求解系统软件,进入主界面:
(1) 输入“1”进入线性方程求解系统模块,输入线性方程组相关系求解,按任意键返回主界
面;
(2)输入“2”进入辅助系统模块,可进行三角函数,ex函数,lgx函数,lnx函数求解,以满
足不同 算函数计算的需求;
(3)输入“0”退出线性方程求界系统软件。
4 软件功能实现
该程序解决了线性方程组求值问题,大大缩短了计算时间。同时还添加了辅助功能,可
以求解三角函数、反三角函数、指数函数、对数函数。
4.1方程组参数输入和存储模块
本模块主要实现对是方程组参数的输入和存储,二维数组是存储方程组参数非常方便的
方法,这样便于用户输入参数和程序的计算。
定义一个二维数组a[i][j],确定线性方程组的方程个(fnumber)和未知数(wunumber)的个
数;输入方程系数和常数,且存储在二维数组,用此语句
{for(i=0;i
程序的相关操作;{for(i=0;i
参数输入语句,这样用户就能输入所求解方程,并且能够实时调整。
4.2方程组初等转换模块
本模块是对矩阵的初等变换,是利用高斯消元法求解方程组的关键步骤,能够把方程组
转换为适合的形式,对程序的求解编写和减小时间复杂度有重要的影响,本模块充分完成了
对高斯法的正确编写。
基于高斯消元法基本思想,为使能逐一对未知量的求解,第一步在初等矩阵中,定出每
列的绝对值最大的一个非0的数,将第一行的值与该行调换,使得第一行拥有这一列的最大
值,每次计算都要记录所用计算次数,所以定义变量(cishu)作为计算次数。用下列语句实现:
for(cishu=1;cishu
{
for(i=j=(cishu-1);i
} else { A[i][j]=a[i][j]; } }//将第i列数值取绝对值放入数组A中 hangmax=j; max=A[cishu-1][j]; for(i=j+1;imax) { hangmax=i; max=A[i][j]; } }//找到第i列的最大值以及所在行 if(hangmax!=j) { i=cishu-1; for(j=0;j
第二步将第一行的数字除以该数,使得该行的第一个数成为1:
{ for(j=i=(cishu-1);j
列的数值依次除以a[i][i],这样就实现了未知量系数的改变。
第三步减去第一行乘以每一行的第一个数,使得每一行的第一个数变为0:
{ a[i][j]=a[i][j]-(temp*a[cishu-1][j]); },这样就完成逐一对未知量的消去,变成了对其中一个
未知量的求解,生成了增广矩阵。
4.3方程组求解判断模块
方程组的解的情况较复杂,有唯一解﹑无解和无数解三种情况,本模块完成了对方程组
解情况的判定和求解表示,系统的表现解的情况。
基于初等变换后,第一行以下的等式中的第一个未知量消除,然后再将第二个以
下的等式中的第二个未知量消除。以此类推,这样可使整个方程组变成一个三角形似
的格式,最后一行变得出其中一个未知量的数值。之后再将已得出的未知量一个个地
代入已被简化的等式中的未知方程中,就可求出其余未知量了。
在模块1中此语句(for(i=0;i
解并进行标记。矩阵转换并计算后,规定biaoji[i]=0表示为无解;biaoji[i]=1表示为有解;
biao[i]=2表示为无穷解。这样就对方程解的情况就行了详细的区分,增强了程序的可操作性。
4.4 辅助计算模块
本模块是对线性方程组求解程序的补充应用,编写对常用函数进行计算程序。
C语言库中含有各种函数库,直接进行调用。此模块可以对三角函数,反三角函数,
e^x, ㏑x㏒x求解计算,并能进行弧度制与角度制进行切换。由于此模块程序计算的函数
较多,选择具有代表性的三角函数计算程序。此程序如下:
if(shuzhileixing=='1')
{
printf("角度值.\n");
}
if(shuzhileixing=='2')
{
printf("弧度值.\n
您输入2即可.(pi=3.1415926535)>\n");
printf("请您配合.否则系统可能不能正常运行!\n");
printf("\a\a");
}
if(ch2=='1')
{
printf("正在为您求解sinx函数.\n");
printf("请您输入x:");
scanf("%lf",&x);
if(shuzhileixing=='2')
{
x1=x*PI;
y=sin(x1);
printf("sin%lfpi=%lf\n",x,y);
}
else
{
x1=(x/180)*PI;
y=sin(x1);
printf("sin%lf度=%lf\n",x,y);
}
}
根据用户输入的不同字符,输入字符1则可以输入任意弧度,输入字符2则可以输入任
意角度,用户可以进行弧度制与角度制间任意切换。
4.5主函数模块
程序需要主函数对各模块函数的调用,这样就不需要把所有的模块函数写在一个主函数
内,便于读懂程序,各模块的分工清晰。
本模块对各模块进行调用,包括xianxingfangchengzuqiujie()函数和fuzhuxitong()函数,
选择字符1,调用 xianxingfangchengzuqiujie();选择字符2,调用fuzhuxitong();选择字符0,
退出。
4.6界面模块
界面模块由主界面和辅助系统界面模块组成,用户输入的字符不同就可以进行相关的计
算,同时规定输入的字符必须符合程序相关的设定,否则在界面中没有反应,这样避免了出
现错误。例如语句{while((ch-'0')2) { ch=getch();}限制了输入字符的范围。函数调
用库函数windows.h文件改变背景和字体颜色,使其背景为淡绿色,字体为亮白色。这样不
仅有了美化效果,更能保护视力。函数更调用了system(”cls”)清屏函数,保证了每个功能
模块有独立的操作界面,改变了单界面的繁杂,简洁明了。
5 调试与操作说明
5.1程序调试分析
本程序在求线性方程组的时候,充分考虑用户输入方程组不同形式和未知量的求解的
不同情况。基于高斯消元法求解多元线性方程核心思想,对程序的调试分析。为扩充程序的
使用能力,对程序功能进行加强,设计了辅助的程序。在调试过程中才用分模块的调试方法,
对程序进行调试分析和改进。
5.2调试结果
5.2.1 开始界面
打开VC6.0,运行线性方程求解系统代码,进入线性方程组求解系统,可看见选择项,
输入“1”进入线性方程组求解模块;输入“2”进入辅助系统;输入“0”退出线性方程组求解操
作系统
图5-1开始界面
5.2.2 方程组求解界面
在主界面输入“1”,进入线性方程组求解模块,按提示输入线性方程组的方程个数和未
知数个数后回车键,再按提示输入每个方程的各项系数和常数,回车键得到线性方程组的解,
若所求线性方程组无解,则会显示方程组无解 ,按任意键可返回主菜单。
图5-2 有解情况的图
求解线性方程组界面,通过输入方程个数和未知数,确定矩阵大小且输入各项系数和常数。
方程组输入完毕按回车键即给出答案。再按任意键返回主菜单。
图5-3 无解情况图
说明:c4为任意常数。
求解线性方程组界面,通过输入方程个数和未知数,确定矩阵大小且输入各项系数和常数。方程组输入完毕按回车键即给出答案。再按任意键返回主菜单。Cx为任意常数,其中未知量用Cx表示,表示为无穷解情况。
图5-4 无穷解情况
选择进入辅助界面, 并通过数字选择计算哪一种函数。
图5-5 辅助程序界面
选择进入求解三角函数界面,并通过数字选择计算哪一个函数。
图 5-6 三角函数求解界面
选择求解sin函数,通过数字控制进入求解sin函数界面,输入x,即给定答案并再次选择“0”返回辅助系统主菜单;“1”继续计算。
图5-7正弦函数求解界面
#include
#include
#include
#include
#define MAX 50
#define PI 3.1415926535
int xianxingfangchengzuqiujie()
{
int i,j,fnumber,hangmax,k,cishu,wu=0,biaoji[MAX],i1,wnumber,number,index; double a[MAX][MAX+1],A[MAX][MAX+1],max,temp,x[MAX],chazhi; char ch;
system("cls");
printf(">>>>>>>>>>>>>>>>>>>>正在为您求解线性方程
组.>>>>>>>>>>>>>>>>>>>>>>>>\n");
printf("请输入线性方程组的方程个数和未知数的个数:\n");
scanf("%d%d",&fnumber,&wnumber);
if(fnumber>=wnumber) { number=fnumber; } else { number=wnumber; } if(fnumber!=wnumber) { for(i=0;i
}//输入系数和常数 } for(i=0;imax) { hangmax=i; max=A[i][j]; } }//找到第i列的最大值以及所在行 if(hangmax!=j) { i=cishu-1; for(j=0;j
} a[i][j]=a[i][j]/temp; }//在第i行中,从第i列到第number列的数值依次除以a[i][i]; for(k=cishu;k=0;i--) { i1=i; if(i1==(number-1)) { if(a[i][i]!=0) { } else { if(a[i][i+1]!=0) { biaoji[i]=0;//标记为无解 chazhi=a[i][number]; x[i+1]=chazhi/a[i][i]; wu++; } else
} else { } } biaoji[i]=2;//标记为无穷解 chazhi=a[i][number]; for(j=i+1;(j
} x[i+1]=chazhi/a[i][i]; } else { } if(chazhi==0) { } else { } biaoji[i]=0; wu++; biaoji[i]=2; } }//根据增广矩阵代入求解 if(wu!=number) { printf("线性方程组的解为:\n"); for(i=1;i
} if(chazhi!=0) { } else { if(a[i-1][i-1]==0) { } else { printf("x%d=",i); printf("x%d=C%d",i,i); printf("x%d=%lf",i,chazhi); for(j=i;j0)) { if(a[i-1][j]!=1) { } else { } printf("-C%d",j+1); printf("%lfC%d",-a[i-1][j],j+1); if((biaoji[j]==1)&&(a[i-1][j]!=0)) { chazhi=chazhi-a[i-1][j]*x[j+1]; } } if((biaoji[j]==2)&&(a[i-1][j]
} { } if((biaoji[j]==2)&&(a[i-1][j]>0)) { if(a[i-1][j]!=1) } { } else { } printf("-C%d",j+1); printf("-%lfC%d",a[i-1][j],j+1); index++; if((biaoji[j]==2)&&(a[i-1][j]
} else } } printf("\n"); { printf("方程组无解!\n"); }//输出结果 for(i=0;i
}
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>按任意键返回主菜
单.>>>>>>>>>>>>>>>>>>>>>>");
ch=getch(); system("cls");
return 0;
}
char zhujiemian()
{
char ch='3'; printf(">>>>>>>>>>>>>>>欢迎您使用线性方程组求解操作系统!>>>>>>>>>>>>>>>>>>>\n");
printf(" 1 - 进入求解系统.\n");
printf(" 2 - 进入辅助系统.\n");
printf(" 0 - 退出.\n"); printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
printf("请输入您的选择:");
while((ch-'0')2) { ch=getch();
}
return ch;
}//主界面
char fuzhuxitongjiemian()
{
char ch='5'; system("cls");
printf(">>>>>>>>>>>欢迎您使用线性方程组求解辅助系统!>>>>>>>>>>>>>>>>>>>>>>>\n");
printf(" 1 - 求解三角函数.\n");
printf(" 2 - 求解e^x函数.\n");
printf(" 3 - 求解lgx函数.\n");
printf(" 4 - 求解lnx函数.\n"); printf(" 0 - 退出.\n");
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
printf("请输入您的选择:");
while((ch-'0')4) { ch=getch(); } system("cls");
return ch;
}//辅助系统界面
int fuzhuxitong()
{
double x,y,x1; int i; char ch,ch1,ch2,ch3,shuzhileixing; while((ch=fuzhuxitongjiemian())!='0') { ch1='1'; if(ch=='1') { while(ch1!='0') {
shuzhileixing='3';
system("cls");
printf(">>>>>>>>>>欢迎您使用三角函数求解操作系统!>>>>>>>>>>>>>>>>\n");
tanx\n");
cota\n");
arctanx\n");
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
printf("请输入您的选择:"); printf(" 1 - sinx 2 - cosx 3 - printf(" 4 - cscx 5 - secx 6 - printf(" 7 - arcsinx 8 - arccosx 9 -
ch2=getch(); while((ch2-'0')9) { ch2=getch(); } system("cls"); if((ch2-'0')>=7) { } shuzhileixing='3'; else { printf("以下是您输入的数值类型:\n"); printf("1 - 角度值. 2 - 弧度值.\n"); printf("请选择您输入的数值类型:"); shuzhileixing=getch(); } ch3='1'; while((shuzhileixing!='1')&&(shuzhileixing!='2')&&(ch2-'0')\n");
if(shuzhileixing=='2')
{
printf("弧度值.\n\n");
printf("请您配合.否则系统可能不能正常运行!\n");
} if(ch2=='1') { printf("正在为您求解sinx函数.\n"); } printf("请您输入x:"); scanf("%lf",&x); if(shuzhileixing=='2') { x1=x*PI; y=sin(x1); printf("\a\a"); printf("sin%lfpi=%lf\n",x,y); } else { x1=(x/180)*PI; y=sin(x1); printf("sin%lf度=%lf\n",x,y); } if(ch2=='2') { printf("正在为您求解cosx函数.\n"); printf("请您输入x:"); scanf("%lf",&x); if(shuzhileixing=='2') { x1=x*PI; y=cos(x1); printf("cos%lfpi=%lf\n",x,y); } else { x1=(x/180)*PI; y=cos(x1); printf("cos%lf度=%lf\n",x,y); } } if(ch2=='3')
{ } { printf("正在为您求解tanx函数.\n"); printf("请您不要输入无解的x.否则答案不正确!\n"); printf("\a\a"); printf("请您输入x:"); scanf("%lf",&x); if(shuzhileixing=='2') { x1=x*PI; y=tan(x1); printf("tan%lfpi=%lf\n",x,y); } else { x1=(x/180)*PI; y=tan(x1); printf("tan%lf度=%lf\n",x,y); } if(ch2=='4') printf("正在为您求解cscx函数.\n"); printf("请您不要输入无解的x.否则答案不正确!\n"); printf("\a\a"); printf("请您输入x:"); scanf("%lf",&x); if(shuzhileixing=='2') { x1=x*PI; y=sin(x1); y=1/y; printf("csc%lfpi=%lf\n",x,y); } else { x1=(x/180)*PI; y=sin(x1); y=1/y; printf("csc%lf度=%lf\n",x,y); } } if(ch2=='5') {
} printf("正在为您求解secx函数.\n"); printf("请您不要输入无解的x.否则答案不正确!\n"); printf("\a\a"); printf("请您输入x:"); scanf("%lf",&x); if(shuzhileixing=='2') { x1=x*PI; y=cos(x1); y=1/y; printf("sec%lfpi=%lf\n",x,y); } else { x1=(x/180)*PI; y=cos(x1); y=1/y; printf("sec%lf度=%lf\n",x,y); } if(ch2=='6') { printf("正在为您求解cotx函数.\n"); printf("请您不要输入无解的x.否则答案不正确!\n"); printf("\a\a"); printf("请您输入x:"); scanf("%lf",&x); if(shuzhileixing=='2') { x1=x*PI; y=tan(x1); y=1/y; printf("cot%lfpi=%lf\n",x,y); } else { x1=(x/180)*PI; y=tan(x1); y=1/y; printf("cot%lf度=%lf\n",x,y); } } if(ch2=='7') {
x=2; while((x>1)||(x=-1):"); scanf("%lf",&x); } else { printf("您的输入有误!请您重新输入.\n"); i++; printf("\a\a"); Sleep(2000); } if(ch2=='8') { i=1; x=2; while((x>1)||(x=-1):"); scanf("%lf",&x); i++; } else system("cls"); printf("您选择输入实际数值.\n"); printf("正在为您求解arcsinx函数.\n"); printf("请您输入x(x=-1):"); scanf("%lf",&x); } } y=asin(x); printf("弧度值: "); printf("arcsin%lf=%lf\n",x,y); y=(180*y)/PI; printf("角度值: "); printf("arcsin%lf=%lf度\n",x,y);
printf("您的输入有误!请您重新输入.\n"); printf("\a\a"); Sleep(2000); system("cls"); printf("您选择输入实际数值.\n"); printf("正在为您求解arccosx函数.\n"); printf("请您输入x(x=-1):"); scanf("%lf",&x); } } y=acos(x); printf("弧度值: "); printf("arccos%lf=%lf\n",x,y); y=(180*y)/PI; printf("角度值: "); printf("arccos%lf=%lf度\n",x,y); } if(ch2=='9') { printf("正在为您求解arctanx函数.\n"); printf("请您输入x:"); scanf("%lf",&x); y=atan(x); printf("弧度值: "); printf("arctan%lf=%lf\n",x,y); y=(180*y)/PI; printf("角度值: "); printf("arctan%lf=%lf度\n",x,y);
}
printf("按'0'返回辅助系统主菜单;按'1'键继续;\n按其余任意键返回三角函数求解主菜单.");
} if(ch=='2') { while(ch1!='0') { } ch3=getch(); if(ch3=='0') { } } ch1=ch3;
printf("正在为您求解e^x函数.\n"); printf("请您输入x:");
scanf("%lf",&x);
y=exp(x);
printf("e^%lf=%lf\n",x,y);
printf("按'0'返回辅助系统主菜单;按其余任意键继续求解e^x函数."); ch1=getch();
} if(ch1!='0') { system("cls");//清屏 } } if(ch=='3') { while(ch1!='0') { x=0; i=1; while(x0):"); scanf("%lf",&x); i++; } else { printf("您的输入有误!请您重新输入.\n"); printf("\a\a"); Sleep(2000); system("cls"); printf("正在为您求解lgx函数.\n"); printf("请您输入x(x>0):"); } scanf("%lf",&x); } y=log10(x); if(x==1) { printf("lg1=0\n"); }
} { printf("lg%lf=%lf\n",x,y); } printf("按'0'返回辅助系统主菜单;按其余任意键继续求解lgx函数."); ch1=getch(); } if(ch1!='0') { } system("cls"); if(ch=='4') { while(ch1!='0') { x=0; i=1; while(x0):"); i++; scanf("%lf",&x); } else { printf("您的输入有误!请您重新输入.\n"); printf("\a\a"); Sleep(2000); system("cls"); printf("正在为您求解lnx函数.\n"); printf("请您输入x(x>0):"); scanf("%lf",&x); } } y=log(x); if(x==1) { printf("ln1=0\n"); } else
printf("ln%lf=%lf\n",x,y); } printf("按'0'返回辅助系统主菜单;按其余任意键继续求解lnx函数."); ch1=getch();
if(ch1!='0')
{
system("cls");
}
}
}
}
return 0;
}
int main()
{
char ch;
system("color 3F");
while((ch=zhujiemian())!='0')
{
if(ch=='1')
{
xianxingfangchengzuqiujie();
}
else
{
fuzhuxitong();
}
}
printf("\n>>>>>>>>>>>感谢您使用
统!>>>>>>>>>>>>>>>>>>>>>>>\n");
Sleep(2000);
return 0;
}//主函数 线性方程组求解操作系