我正在尝试在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);
}
答案 0 :(得分:2)
上述代码中存在许多问题。由于数组在C中是零索引的,因此您应该从零开始计算矩阵的行和列,而不是从1开始计数,然后在数组索引时尝试转换。无需转换malloc()
的结果,最好使用标识符而不是显式类型作为sizeof
运算符的参数:
A = malloc(sizeof(*A) * n * n));
您在L
中为R
和main()
分配空间,然后在程序结束时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);
中执行高斯消元的实际算法被破坏。除此之外,调用k
将i0
行与i0
行交换,但k
是b
行的数据透视列。这毫无意义。
实际上看起来你想做的不仅仅是用这个代码计算行列式,因为你有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}}