You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用C语言求N阶矩阵的逆?高阶行列式计算异常求助

问题分析与解决方案

你遇到的核心问题并非行列式计算模块本身,而是余子矩阵的存储逻辑错误导致逆矩阵计算异常,同时pow函数的浮点数精度可能带来微小误差。以下是具体分析和修复方案:

1. 核心错误:余子矩阵存储位置颠倒

cofactor函数中,你计算的是第q行第p列元素的余子式,但错误地将其赋值给了fac[p][q](行列颠倒)。后续的转置操作会进一步放大这个错误,最终得到的不是伴随矩阵,而是余子矩阵本身,导致逆矩阵计算完全错误。

修复方式
fac[p][q] = x;改为fac[q][p] = x;,确保余子式值存储到正确的行列位置。

2. 次要问题:pow函数的精度隐患

使用pow(-1, q+p)计算符号时,浮点数运算可能产生微小的精度误差(例如-1.0变成-0.9999999999),这会影响最终的行列式和逆矩阵结果。建议改用整数奇偶性判断来替代:

修复方式
x = pow(-1, q + p) * determinant( tam - 1,b);改为:

int sign = ((q + p) % 2 == 0) ? 1 : -1;
x = sign * determinant(tam - 1, b);

3. 额外bug:main函数中flag未初始化

main函数里的flag变量没有初始值,导致输入合法矩阵后循环可能无法终止。需要初始化flag为0,并在处理完合法矩阵后将其设为1。

修复方式
main函数开头添加flag = 0;,并在create_Matrix(line);后添加flag = 1;

修正后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<math.h>

float determinant(int tam, float[][tam]);
void cofactor(int tam, float[][tam]);
void transpose(int tam, float[][tam], float[][tam]);

int validate() {
    int val;
    char *buf = (char *)malloc(10);
    memset(buf, 0, 10);
    while (fgets(buf, 10, stdin) != NULL) {
        if (buf[0] != '\n') {
            val = atoi(buf);
            break;
        }
    }
    free(buf);
    return val;
}

float determinant(int tam, float matrix[][tam]) {
    float s = 1, det = 0, b[tam][tam];
    int i, j, m, n, c;
    if (tam == 1) {
        return (matrix[0][0]);
    } else {
        det = 0;
        for (c = 0; c < tam; c++) {
            m = 0;
            n = 0;
            // 初始化子矩阵为0
            for (i = 0; i < tam; i++) {
                for (j = 0; j < tam; j++) {
                    b[i][j] = 0;
                }
            }
            for (i = 0; i < tam; i++) {
                for (j = 0; j < tam; j++) {
                    if (i != 0 && j != c) {
                        b[m][n] = matrix[i][j];
                        if (n < (tam - 2)) {
                            n++;
                        } else {
                            n = 0;
                            m++;
                        }
                    }
                }
            }
            det = det + s * (matrix[0][c] * determinant(tam - 1, b));
            s = -1 * s;
        }
    }
    return (det);
}

void cofactor(int tam, float num[][tam]) {
    float b[tam][tam], fac[tam][tam];
    int p, q, m, n, i, j;
    float x = 0;
    for (q = 0; q < tam; q++) {
        for (p = 0; p < tam; p++) {
            m = 0;
            n = 0;
            // 初始化子矩阵为0
            for (i = 0; i < tam; i++) {
                for (j = 0; j < tam; j++) {
                    b[i][j] = 0;
                }
            }
            for (i = 0; i < tam; i++) {
                for (j = 0; j < tam; j++) {
                    if (i != q && j != p) {
                        b[m][n] = num[i][j];
                        if (n < (tam - 2)) {
                            n++;
                        } else {
                            n = 0;
                            m++;
                        }
                    }
                }
            }
            // 用整数判断替代pow,避免精度问题
            int sign = ((q + p) % 2 == 0) ? 1 : -1;
            x = sign * determinant(tam - 1, b);
            // 修复余子式存储位置
            fac[q][p] = x;
        }
    }
    transpose(tam, num, fac);
}

void transpose(int tam, float num[][tam], float fac[][tam]) {
    int i, j;
    float b[tam][tam], inverse[tam][tam], d;
    // 转置余子矩阵得到伴随矩阵
    for (i = 0; i < tam; i++) {
        for (j = 0; j < tam; j++) {
            b[i][j] = fac[j][i];
        }
    }
    d = determinant(tam, num);
    for (i = 0; i < tam; i++) {
        for (j = 0; j < tam; j++) {
            inverse[i][j] = b[i][j] / d;
        }
    }
    printf("\n\n\nThe inverse of matrix is : \n");
    for (i = 0; i < tam; i++) {
        for (j = 0; j < tam; j++) {
            printf("\t%f", inverse[i][j]);
        }
        printf("\n");
    }
}

int verify_Size(int line) {
    if ((line > 0) && (line <= 6)) {
        return 1;
    }
    return 0;
}

int create_Matrix(int LINE) {
    int matrix[LINE][LINE];
    float aux[LINE][LINE];
    printf("\n\n\nPlease enter %d elements:\n", (LINE * LINE));
    printf("--------------------------------\n");
    for (int i = 0; i < LINE; i++) {
        for (int j = 0; j < LINE; j++) {
            printf("Value[%d][%d]: ", i, j);
            matrix[i][j] = validate();
        }
    }
    printf("\n\nYour Bidimensional Matrix is:");
    printf("\n--------------------------------\n");
    for (int i = 0; i < LINE; i++) {
        for (int j = 0; j < LINE; j++) {
            printf("\t%2d", matrix[i][j]);
            aux[i][j] = (float)matrix[i][j];
        }
        printf("\n");
    }
    float d = determinant(LINE, aux);
    printf("\n\nDeterminant: %f \n", d);
    if (fabs(d) < 1e-6) { // 用浮点比较替代==0,避免精度问题
        printf("\nInverse of Entered Matrix is not possible\n");
    } else {
        cofactor(LINE, aux);
    }
    return 0;
}

int main() {
    int flag = 0, line; // 初始化flag
    do {
        printf("Enter the order of the Matrix:\n");
        printf("-------------------------------\n");
        printf("Lines: ");
        line = validate();
        if (verify_Size(line) == 1) {
            create_Matrix(line);
            flag = 1; // 设置flag为1,终止循环
        } else {
            printf("\nMatrix must be up to 6 X 6!\n");
            flag = 0;
        }
    } while (flag != 1);
    return 0;
}

额外优化点

  • create_Matrix中,判断行列式是否为0时,用fabs(d) < 1e-6替代d == 0,避免浮点数精度误差导致的误判。
  • 将子矩阵的初始化逻辑移到填充之前,确保所有元素初始为0,避免垃圾值干扰。

内容的提问来源于stack exchange,提问作者Rafael Rossales

火山引擎 最新活动