c中的矩阵行列式使用高斯消除核心转储错误

时间:2017-01-16 14:26:54

标签: c pointers gaussian

我正在尝试在C中创建一个简单的控制台应用程序,它将使用高斯消除来计算矩阵的行列式。经过大量测试后,我发现我的程序由于核心转储错误而无法正常工作。经过2天的编辑和撤消,我找不到问题。 任何帮助都受到欢迎。

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

int recherche_pivot(int k, int n, float *A)
{
    int i, j;
    if (A[((k - 1) * n + k) - 1] != 0)
    {
        return k;
    }
    else
    { //parcours du reste de la colonne
        for (i = k + 1; i <= n; i++)
        {
            if (A[((k - 1) * n + i) - 1] != 0)
            {
                return i;
            }
        }
        return -1;
    }
}

void fois(int n, float p, int i, float * A, float *b, float * x)
{
    int a;
    for (a = 1; a <= n; a++)
    {
        x[a - 1] = A[((i - 1) * n + a) - 1] * p;
    }
    x[n] = b[i - 1] * p;
}
void afficher_system(int n, float * X, float *b)
{
    int i, j;
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
            printf("%f  ", X[((i - 1) * n + j) - 1]);
        printf(" | %f", b[i - 1]);
        printf("nn");
    }
    printf("nnnn");
}

void saisirmatrice(int n, float *A)
{
    int i, j;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            scanf("%f", &A[((i - 1) * n + j) - 1]);
}

void affichermatrice(int n, float *A)
{
    int i, j;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            printf("A[%d][%d] = %fn", i, j, A[((i - 1) * n + j) - 1]);
}

void elemination(int n, int k, float *b, float *A)
{
    int i, l, j;
    float * L, piv;
    L = (float *) malloc((n) * sizeof(float));
    for (i = k + 1; i <= n; i++)
    {
        piv = -1 * (A[((i - 1) * n + k) - 1] / A[((k - 1) * n + k) - 1]);
        fois(n, piv, k, A, b, L);
        //afficher_vecteur(n,L);
        for (j = 1; j <= n; j++)
        {
            A[((i - 1) * n + j) - 1] = A[((i - 1) * n + j) - 1] + L[j - 1];
        }
        b[i - 1] = b[i - 1] + L[n];
        afficher_system(n, A, b);
    }
}

void permutter(int n, float * A, int i, int j, float * b)
{
    int a;
    float t[n + 1];
    for (a = 1; a <= n; a++)
    {
        t[a - 1] = A[((i - 1) * n + a) - 1];
        A[((i - 1) * n + a) - 1] = A[((j - 1) * n + a) - 1];
        A[((j - 1) * n + a) - 1] = t[a - 1];
    }
    t[n] = b[i - 1];
    b[i - 1] = b[j - 1];
    b[j - 1] = t[n];
}

void main()
{
    float * A, det, *L, *R, *b, s;
    int i, j, i0, n, k, stop = 0;

    printf("Veuillez donner la taille de la matrice");
    scanf("%d", &n);
    A = (float *) malloc(sizeof(float) * (n * n));
    L = (float*) malloc(n * sizeof(float));
    R = (float*) malloc(n * sizeof(float));
    b = (float*) malloc(n * sizeof(float));
    printf("Veuillez remplir la matrice");
    saisirmatrice(n, A);
    det = 1;
    stop = 0;
    k = 1;
    do
    {
        do
        {
            i0 = recherche_pivot(k, n, A);
            if (i0 == k)
            {
                //Elémination
                elemination(n, k, b, A);
                k++;
            }
            else if (i0 == -1)
            {
                stop = 1;
            }
            else
            { //cas ou ligne pivot=i0 != k
              //permutation
                det = -det;
                permutter(n, A, k, i0, b);
                //elemination
                elemination(n, k, b, A);
                //afficher_matrice(n,A);
                k++;

            }
        } while ((k <= n) && (stop == 0));
    } while (stop == 1 || k == n);

    for (i = 1; i < n; i++)
    {
        det = det * A[((i - 1) * n + i) - 1];
    }

    printf("Le determinant est :%f", det);
    free(A);
    free(L);
    free(R);
    free(b);
}

1 个答案:

答案 0 :(得分:2)

上述代码中存在许多问题。由于数组在C中是零索引的,因此您应该从零开始计算矩阵的行和列,而不是从1开始计数,然后在数组索引时尝试转换。无需转换malloc()的结果,最好使用标识符而不是显式类型作为sizeof运算符的参数:

A = malloc(sizeof(*A) * n * n));

您在L中为Rmain()分配空间,然后在程序结束时free d之前从不使用这些指针。然后在L函数中分配elemination();但你永远不会free这个记忆,所以你有内存泄漏。您还可以在b中为main()分配空间,但在将b传递给elemination()函数之前,不要将其存储在recherche_pivot()中。这肯定会引起问题。

首先不需要动态分配;我建议使用可变长度数组来存储矩阵的元素。这些已经从C99开始提供,并且可以避免所有分配问题。

if(A[((k - 1) * n + i) - 1] != 0) {} 功能存在问题,您可以在其中进行比较:

DELTA

这是一个问题,因为数组元素是一个浮点值,它是算术运算的结果;此值不应与 0 直接比较。我建议选择适当的#define DELTA 0.000001 ... if (fabs(A[((k - 1) * n + i) - 1]) < DELTA) {} 值来表示零范围,而不是比较:

permutter()

float t[n];函数中,您使用数组float t;来保存临时值。但是这里不需要数组,因为你不需要在交换后保存这些临时值;而只是使用b[]。此外,当您在t[n]中交换值时,使用elemination()来存储临时值,但这超出了范围。

k函数应该迭代所有行(k行除外),而不是从k+1行开始,或者它应该从k行开始{1}}行。实际上,main()行用于消除自身。最后,用于在permutter(n, A, k, i0, b);中执行高斯消元的实际算法被破坏。除此之外,调用ki0行与i0行交换,但kb行的数据透视列。这毫无意义。

实际上看起来你想做的不仅仅是用这个代码计算行列式,因为你有reduce(),它是线性系统的常量向量。您的问题标题中提到的任务不需要这样做。此外,您的代码似乎为任何 1X1 决定因素提供 1 的结果。这是不正确的;在这种情况下,它应该是单个数字的值。

用于计算行列式的高斯消元法要求您跟踪执行的行交换次数,并保留各个行乘以的任何因子的运行乘积。将一行的多个行添加到另一行以替换该行不会更改行列式的值,这是下面signed int函数中使用的操作。最终结果是简化矩阵中对角线条目的乘积,每次行交换操作乘以 -1 一次,除以用于缩放各行的所有因子的乘积。在这种情况下,没有这样的因素,因此结果只是简化矩阵的对角元素与符号校正的乘积。这是原始问题中发布的代码所使用的方法。

这里有很多问题,我刚刚写了一个实现这个算法的新程序。我认为,至少在精神上,它与你想要完成的事情相近。我确实为矩阵的大小添加了一些输入验证,检查以确保用户输入正数,并在输入错误时提示重新输入。填充矩阵的输入循环将受益于类似的输入验证。另请注意,输入大小存储在size_t中,以允许检查负输入,并成功输入并存储在unsigned类型的变量中,这是size_t整数类型保证保存任何数组索引。这是索引数组时使用的正确类型,您将注意到整个程序中使用了#include <stdio.h> #include <math.h> #include <stdbool.h> #define DELTA 0.000001 void show_matrix(size_t mx_sz, double mx[mx_sz][mx_sz]); void interchange(size_t r1, size_t r2, size_t mx_sz, double mx[mx_sz][mx_sz]); void reduce(double factor, size_t r1, size_t r2, size_t mx_sz, double mx[mx_sz][mx_sz]); size_t get_pivot(size_t row, size_t mx_sz, double mx[mx_sz][mx_sz]); double find_det(size_t mx_sz, double mx[mx_sz][mx_sz]); int main(void) { size_t n; int read_val, c; printf("Enter size of matrix: "); while (scanf("%d", &read_val) != 1 || read_val < 1) { while ((c = getchar()) != '\n' && c != EOF) { continue; // discard extra characters } printf("Enter size of matrix: "); } n = (size_t) read_val; double matrix[n][n]; printf("Enter matrix elements:\n"); for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < n; j++) { scanf("%lf", &matrix[i][j]); } } printf("You entered:\n"); show_matrix(n, matrix); putchar('\n'); double result = find_det(n, matrix); show_matrix(n, matrix); putchar('\n'); printf("Determinant: %f\n", result); return 0; } void show_matrix(size_t n, double mx[n][n]) { for (size_t i = 0; i < n; i++) { for (size_t j = 0; j < n; j++) { printf("%7.2f", mx[i][j]); } putchar('\n'); } } /* interchange rows r1 and r2 */ void interchange(size_t r1, size_t r2, size_t mx_sz, double mx[mx_sz][mx_sz]) { double temp; for (size_t j = 0; j < mx_sz; j++) { temp = mx[r1][j]; mx[r1][j] = mx[r2][j]; mx[r2][j] = temp; } } /* add factor * row r1 to row r2 to replace row r2 */ void reduce(double factor, size_t r1, size_t r2, size_t mx_sz, double mx[mx_sz][mx_sz]) { for (size_t j = 0; j < mx_sz; j++) { mx[r2][j] += (factor * mx[r1][j]); } } /* returns pivot column, or mx_sz if there is no pivot */ size_t get_pivot(size_t row, size_t mx_sz, double mx[mx_sz][mx_sz]) { size_t j = 0; while (j < mx_sz && fabs(mx[row][j]) < DELTA) { ++j; } return j; } double find_det(size_t mx_sz, double mx[mx_sz][mx_sz]) { size_t pivot1, pivot2; size_t row; double factor; bool finished = false; double result = 1.0; while (!finished) { finished = true; row = 1; while (row < mx_sz) { // determinant is zero if there is a zero row if ((pivot1 = get_pivot(row - 1, mx_sz, mx)) == mx_sz || (pivot2 = get_pivot(row, mx_sz, mx)) == mx_sz) { return 0.0; } if (pivot1 == pivot2) { factor = -mx[row][pivot1] / mx[row - 1][pivot1]; reduce(factor, row - 1, row, mx_sz, mx); finished = false; } else if (pivot2 < pivot1) { interchange(row - 1, row, mx_sz, mx); result = -result; finished = false; } ++row; } } for (size_t j = 0; j < mx_sz; j++) { result *= mx[j][j]; } return result; }

Enter size of matrix: oops
Enter size of matrix: 0
Enter size of matrix: -1
Enter size of matrix: 3
Enter matrix elements:
0 1 3
1 2 0
0 3 4
You entered:
   0.00   1.00   3.00
   1.00   2.00   0.00
   0.00   3.00   4.00

   1.00   2.00   0.00
  -0.00  -3.00  -9.00
   0.00   0.00  -5.00

Determinant: 5.000000

示例会话:

{{1}}