矩阵行交换实现无零对角线上三角矩阵的代码问题排查
问题
尝试通过对角线元素相乘计算矩阵行列式,已实现将矩阵转为上三角矩阵的逻辑,但对角元出现零时,行交换功能失效。测试矩阵如下:
4 7 -2 3 8 2 -4 5 3 0 9 -6 4 5 -2 4 8 3 0 1 -8 4 6 5 2
需将上述矩阵保存为.txt文件,代码指定路径读取。当前代码输出与输入矩阵一致,本该交换最后两行却未执行,代码如下:
#include<stdio.h> #include<math.h> #define MAX 100 int main() { FILE *fr; int i,j,k,m=0,q=0,count=1; double cache; double ratio, det = 1; int n = 0; char c; char subor[MAX]; printf("Input the name of your file: "); scanf("%s", subor); fr = fopen(subor,"r"); if (fr == NULL) { printf("Unable to open file: %s", subor); return 0; } for (c = getc(fr); c != EOF; c = getc(fr)) if (c == '\n') n = n + 1; fclose(fr); printf("\nDimensions of the given matrix: %dx%d\n\n", subor, n, n); fr =fopen(subor,"r"); float a[n][n]; printf("Matrix:\n"); for(i=0;i< n;i++) { for(j=0;j< n;j++) { fscanf(fr, "%g%*c",&a[i][j]); printf("%g\t",a[i][j]); } printf("\n"); } fclose(fr); while(a[m][m] == 0.0 && m != n) { q=m; while(a[m][m] == 0.0 && q != n) { for(i=0;i<n;i++) { cache=a[m][i]; a[m][i]=a[q+1][i]; a[q+1][i]=cache; count = count*(-1); } ++q; } ++m; } printf("\nEdited: \n"); for(i=0;i< n;i++) { for(j=0;j< n;j++) { printf("%g\t",a[i][j]); } printf("\n"); return 0; }
问题排查与修复
核心问题分析
- 行交换逻辑错误:内层循环直接交换
m行和q+1行,未先检查目标行的对应列元素是否非零,且当q等于n-1时,q+1会越界访问非法内存。 - 浮点数比较精度问题:直接用
a[m][m] == 0.0判断浮点数是否为零,易因精度误差导致判断失误。 - 维度输出参数错误:
printf输出矩阵维度时参数不匹配,多余的subor会导致输出错乱。 - 输入读取逻辑缺陷:
%*c会强制读取一个字符,可能错误消耗矩阵元素的分隔符,导致读取异常。
修复后的代码
#include<stdio.h> #include<math.h> #define MAX 100 #define EPS 1e-9 // 浮点数精度阈值,避免精度误差导致的零判断错误 int main() { FILE *fr; int i,j,m=0,count=1; double cache; int n = 0; char c; char subor[MAX]; printf("Input the name of your file: "); scanf("%s", subor); fr = fopen(subor,"r"); if (fr == NULL) { printf("Unable to open file: %s", subor); return 0; } // 统计矩阵行数:最后一行可能无换行符,初始值设为1 n = 1; for (c = getc(fr); c != EOF; c = getc(fr)) { if (c == '\n') n++; } fclose(fr); printf("\nDimensions of the given matrix: %dx%d\n\n", n, n); fr = fopen(subor,"r"); float a[n][n]; printf("Matrix:\n"); for(i=0;i< n;i++) { for(j=0;j< n;j++) { fscanf(fr, "%g", &a[i][j]); // 去掉%*c,自动适配空格/制表符分隔 printf("%g\t",a[i][j]); } printf("\n"); } fclose(fr); // 处理对角元为零的行交换逻辑 while(m < n) { // 判断当前对角元是否接近零 if(fabs(a[m][m]) < EPS) { int swap_row = -1; // 从当前行下方寻找第m列非零的行 for(i = m+1; i < n; i++) { if(fabs(a[i][m]) > EPS) { swap_row = i; break; } } // 找到可交换的行则执行交换 if(swap_row != -1) { for(j=0;j<n;j++) { cache = a[m][j]; a[m][j] = a[swap_row][j]; a[swap_row][j] = cache; } count *= -1; // 行交换一次,行列式符号反转 } else { // 第m列全为零,矩阵奇异,行列式为0 printf("\nMatrix is singular, determinant is 0.\n"); return 0; } } m++; } printf("\nEdited: \n"); for(i=0;i< n;i++) { for(j=0;j< n;j++) { printf("%g\t",a[i][j]); } printf("\n"); } // 计算行列式:上三角矩阵对角元乘积 × 行交换符号 double det = count; for(i=0;i<n;i++) { det *= a[i][i]; } printf("\nDeterminant: %g\n", det); return 0; }
修复说明
- 修正行交换逻辑:先从当前行下方寻找对应列非零的行,找到后再执行交换,避免无效操作和越界访问。
- 解决浮点数精度问题:用
fabs(a[m][m]) < EPS判断是否为零,适配浮点数计算的精度误差。 - 修复输出与输入逻辑:调整矩阵维度输出的参数,优化输入读取方式,避免分隔符导致的读取错误。
- 补充行列式计算:完成行交换后,直接计算上三角矩阵的行列式,完善功能。
内容的提问来源于stack exchange,提问作者Tomas Makuch
相关产品推荐
相关产品推荐

