情况是这样,我->对象->C语言作业->解线性方程组。
高斯消元解法的思想就是,对系数矩阵A做初等行变换,得到一个上三角矩阵,从最后一行开始,逐个解方程组。
这里考虑的情况是系数矩阵A满秩,所以最后一行只有对角线上有一个非零元素,可以直接得到 x n x_n xn的解;
它的上一层有两个非零元素,其中 x n x_n xn已求得,故可以一步计算出 x n − 1 x_{n-1} xn−1;
…
依此类推,便可以求得所有的未知数 x 1 , 2 , . . . , n x_{1,2,...,n} x1,2,...,n。
//这里函数把A处理为上三角矩阵,但没有处理为标准上三角矩阵,即不保证每一行的首个非零元素为1
void rowTrans(double array[MAX][MAX], int n){
// 做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array,i,i+(k++),n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
解系数矩阵A为上三角方程组的函数:
void solveUpperEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为上三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=n-1;i>=0;i--){
for(j=i+1;j<n;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
再补充一个解系数矩阵A为下三角方程组的函数:
void solveLowerEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为下三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=0;i<n;i++){
for(j=0;j<i;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
一些工具函数:
//输出矩阵内容
void printMatrix(double array[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%lf",array[i][j]);
if(j==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
}
//输出数组内容
void printArray(double x[MAX], int n){
int i;
for(i=0;i<n;i++){
printf("%lf",x[i]);
if(i==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
//交换函数
void swap(double* a,double*b){
double tmp = *a;
*a = *b;
*b = tmp;
}
//交换数组元素
void swapArray(double array[MAX][MAX],int a,int b,int n){
int i;
for(i=0;i<n;i++)
swap(&array[a][i],&array[b][i]);
}
void copyMatrix(double a[MAX][MAX], double b[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;i++){
b[i][j]=a[i][j];
}
}
}
void copyArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++){
b[i]=a[i];
}
}
完整代码如下:
#include
#include
#define MAX 20
void swap(double* a,double*b){
double tmp = *a;
*a = *b;
*b = tmp;
}
void swapArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++)
swap(&a[i],&b[i]);
}
double computeDet(double array[MAX][MAX], int n){
// 通过初等行变换,再计算对角元素乘积,来计算行列式的值
int i,j,k;
int sign=0; //行列式交换一次需要改变符号,此变量记录交换次数
double sum=1.0; //结果
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
sign++;
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
for(i=0;i<n;i++)
sum *= array[i][i];
if(sign%2!=0) //交换偶数次符仍为正
sum *= -1;
return sum;
}
void rowTrans(double array[MAX][MAX], int n){
// 做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void rowTrans_Ab(double array[MAX][MAX], int n){
// 做A、b同时做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<=n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void printMatrix(double array[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%lf",array[i][j]);
if(j==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
}
void printArray(double x[MAX], int n){
int i;
for(i=0;i<n;i++){
printf("%lf",x[i]);
if(i==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
void copyMatrix(double a[MAX][MAX], double b[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;i++){
b[i][j]=a[i][j];
}
}
}
void copyArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++){
b[i]=a[i];
}
}
void solveLowerEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为下三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=0;i<n;i++){
for(j=0;j<i;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
void solveUpperEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为上三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=n-1;i>=0;i--){
for(j=i+1;j<n;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
//解一般方程
int main(){
int i,j;
int n; //阶数
double tmp; //临时变量
double x[MAX]; //未知数矩阵
double b[MAX]; //常系数矩阵
double A[MAX][MAX]; //系数矩阵
//数据初始化
printf("Please enter the dimensions of the coefficient matrix:(n)");
scanf("%d",&n);
printf("Please enter the value of coefficient matrix:(A)\n");
for(i=0;i<n;i++){
for(j=0;j<n;j++)
scanf("%lf",&A[i][j]);
}
printf("Please enter the value of the constant term matrix:(b)\n");
for(i=0;i<n;i++){
scanf("%lf",&b[i]);
}
//初始化x和Ab
for(i=0;i<n;i++){
x[i]=0.0;
A[i][n]=b[i];
}
//对矩阵A做初等行变换
rowTrans_Ab(A,n);
printf("rowTrans:\n");
printMatrix(A,n);
//取变化后的b
for(i=0;i<n;i++){
b[i]=A[i][n];
}
//解上三角矩阵
solveUpperEquations(A,x,b,n);
//输出结果
printf("The result are:\n");
printArray(x,n);
return 0;
}
Cholesky分解又称平方分解法,是把一个正定对称的矩阵表示成一个下三角矩阵L和其转置的乘积的分解。
已知,满秩矩阵可以做LU分解,同理也可以LDU分解。
对于一个正定对称矩阵,它显然也可以做LDU分解,不过特殊的是,把D对角线上的每个元素都开平方,分别乘给L和U,则可以得到 L L L和 L T L^T LT,使得 A = L ∗ L T A=L*L^T A=L∗LT。
我使用的求法是,给系数矩阵A做(没有整除某个非零数的,即不刻意得把每一行的非零首元化为1)初等行变换,得到上三角矩阵。该方法得到的上三角矩阵即为DU,对D对角线上的每个元素做平方处理,得到的结果再与U相乘,即得到 L T L^T LT。
#include
#include
#define MAX 20
void swap(double* a,double*b){
double tmp = *a;
*a = *b;
*b = tmp;
}
void swapArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++)
swap(&a[i],&b[i]);
}
double computeDet(double array[MAX][MAX], int n){
// 通过初等行变换,再计算对角元素乘积,来计算行列式的值
int i,j,k;
int sign=0; //行列式交换一次需要改变符号,此变量记录交换次数
double sum=1.0; //结果
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
sign++;
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
for(i=0;i<n;i++)
sum *= array[i][i];
if(sign%2!=0) //交换偶数次符仍为正
sum *= -1;
return sum;
}
void rowTrans(double array[MAX][MAX], int n){
// 做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n-1;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void rowTrans_Ab(double array[MAX][MAX], int n){
// 做A、b同时做初等行变换
int i,j,k;
double tmp; //暂存乘积因子
double zero=1e-6; //两浮点数差距小于1e-6视为相等
for(i=0;i<n;i++){
k=1;
while(fabs(array[i][i]-0.0)<zero && i+k<n){
swapArray(array[i],array[i+(k++)],n);
}
for(j=i+1;j<n;j++){
if(array[j][i]==0.0) //如为0则那一行不用化简
continue;
else{
tmp = -(double)array[j][i]/array[i][i]; //保存乘积因子
for(k=i;k<=n;k++)
array[j][k] += (tmp*array[i][k]);
}
}
}
}
void printMatrix(double array[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
printf("%lf",array[i][j]);
if(j==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
}
void printArray(double x[MAX], int n){
int i;
for(i=0;i<n;i++){
printf("%lf",x[i]);
if(i==n-1){
printf("\n");
}else{
printf("\t");
}
}
}
void copyMatrix(double a[MAX][MAX], double b[MAX][MAX], int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;i++){
b[i][j]=a[i][j];
}
}
}
void copyArray(double a[MAX], double b[MAX], int n){
int i;
for(i=0;i<n;i++){
b[i]=a[i];
}
}
void transpose(double a[MAX][MAX], int n){
int i,j;
for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
swap(&a[i][j], &a[j][i]);
}
}
}
void solveLowerEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为下三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=0;i<n;i++){
for(j=0;j<i;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
void solveUpperEquations(double A[MAX][MAX], double x[MAX], double b[MAX], int n){
//求解系数矩阵为上三角矩阵的线性方程组
int i,j;
copyArray(b,x,n);
for(i=n-1;i>=0;i--){
for(j=i+1;j<n;j++){
x[i]-=A[i][j]*x[j];
}
x[i]/=A[i][i];
}
}
int main(){
int i,j;
int n; //阶数
double tmp; //临时变量
double x[MAX]; //未知数矩阵
double A[MAX][MAX]; //系数矩阵
double b[MAX]; //常系数矩阵
//数据初始化
printf("Please enter the dimensions of the coefficient matrix:(n)");
scanf("%d",&n);
printf("Please enter the value of coefficient matrix:(A)\n");
for(i=0;i<n;i++){
for(j=0;j<n;j++)
scanf("%lf",&A[i][j]);
}
printf("Please enter the value of the constant term matrix:(b)\n");
for(i=0;i<n;i++){
scanf("%lf",&b[i]);
}
for(i=0;i<n;i++){
x[i]=0.0;
}
//对矩阵A做初等行变换
rowTrans(A,n);
printf("rowTrans:\n");
printMatrix(A,n);
//处理主元,得到L.T(上三角矩阵)
for(i=0;i<n;i++){
if(A[i][i]<0){
for(j=i;j<n;j++){
A[i][j]*=-1;
}
}
if(A[i][i]!=1){
tmp=sqrt(A[i][i]);
for(j=i;j<n;j++){
A[i][j]/=tmp;
}
}
}
printf("L.T:\n");
printMatrix(A,n);
//求得L(下三角矩阵),求解第一步方程Ly=b,求得y
transpose(A,n);
printf("L:\n");
printMatrix(A,n);
solveLowerEquations(A,x,b,n);
printf("y:\n");
printArray(x,n);
//求得L.T(上三角矩阵),求解第二步方程L.T*x=y,求得x
transpose(A,n);
copyArray(x,b,n);//x中暂存的y赋给b
solveUpperEquations(A,x,b,n);
printf("The result are:\n");
printArray(x,n);
return 0;
//期望结果:(1,-1,0,2,1,-1,0,2)
}