Reputation: 29
im currently trying to write a program to find the determinant for an NxN matrix but im having an issue with recursion for N larger than 2. Basically from what i can tell, it isn't doing it, it just runs the function once as using my debug option shows that the function runs through the columns but the order never goes down, and it then gives me zero for my determinant no matter what. Ive tried looking all over the place for any idea as to what im doing wrong but i cant seem to find any answers, ive even found examples which do basically the same thing as me and using them gives me zero no matter what as well, so im very confused :(. id be very grateful if someone could have a quick look through my code and tell me where im being an idiot! (sorry about the formatting, it looks ok in my editor but i cant seem to get the hang of it on here)
Code:
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
double det(double **mat, int order);
int main (int argc, char* argv[])
{
FILE* input;
int row,column,N;
double **matrix;
N=3;
matrix=(double**)malloc(N*sizeof(double));
input=fopen("matrix.dat", "r");
if(input !=(FILE*) NULL)
{
for(row=0; row<N; row++)
{
matrix[row]=(double*)malloc(N*sizeof(double));
}
for(row=0; row<N; row++)
{
printf("| ");
for(column=0; column<N; column++)
{
fscanf(input,"%lf ", &matrix[row][column]);
printf("%g ", matrix[row][column]);
}
if(row != (N/2))
{
printf("|\n");
}
else
{
printf("|= %lf \n", det(matrix, N) );
}
}
return(EXIT_SUCCESS);
}
else
{
printf("*********************ERROR*********************\n");
printf("** Cannot open input file 'matrix.dat' make **\n");
printf("** sure file is present in working directory **\n");
printf("***********************************************\n");
return(EXIT_FAILURE);
}
}
double det(double **mat, int order)
{
int debug;
double cofact[order], determinant, **temp;
determinant = 0;
debug=0;
if(order==1)
{
determinant=mat[0][0];
if(debug==1)
{
printf("order 1 if\n");
}
}
else if(order==2)
{
determinant= ((mat[0][0]*mat[1][1])-(mat[0][1]*mat[1][0]));
if(debug==1)
{
printf("order 2 if\n");
}
}
else
{
int column, rowtemp, coltemp, colread;
for (column=0; column<order; column++)
{
/* Now create an array of size N-1 to store temporary data used for calculating minors */
temp= malloc((order-1)*sizeof(*temp));
for(rowtemp=0; rowtemp<(order-1); rowtemp++)
{
/* Now asign each element in the array temp as an array of size N-1 itself */
temp[rowtemp]=malloc((order-1)*sizeof(double));
}
for(rowtemp=1; rowtemp<order; rowtemp++)
{
/* We now have our empty array, and will now fill it by assinging row and collumn values from the original mat with the aprroriate elements excluded */
coltemp=0;
for(colread=0; colread<order; colread++)
{
/* When the collumn of temp is equal to the collumn of the matrix, this indicates this row should be exlcuded and is skiped over */
if(colread==column)
{
continue;
}
temp[rowtemp-1][coltemp] = mat[rowtemp][colread];
coltemp++;
}
}
if(debug==1)
{
printf("column =%d, order=%d\n", column, order);
}
determinant+=(mat[0][column]*(1 - 2*(column & 1))*det(temp, order-1));
}
}
return(determinant);
}
Upvotes: 1
Views: 4580
Reputation: 183878
temp= (double **)malloc((order-1)*sizeof(double));
This will not cause a crash as long as sizeof(double*) <= sizeof(double)
, which is the case on the usual 32 or 64-bit systems, but it is conceptually wrong. You are allocating space for an array of double*
, so the factor should be sizeof(double*)
or, better since it is invariant when the type changes, sizeof *temp
,
temp = malloc((order-1) * sizeof *temp);
(And you don't need to cast the result of malloc
in C, it is even better not to, since the cast could hide errors like forgetting to #include <stdlib.h>
.)
The same holds for the allocation
matrix=(double**)malloc(N*sizeof(double));
in main
.
In the calculation of the determinant,
for(coltemp=0; coltemp<order; coltemp++)
{
for(colread=0; colread<order; colread++)
{
/* When the collumn of temp is equal to the collumn of the matrix, this indicates this row should be exlcuded and is skiped over */
if(colread==column)
{
continue;
}
temp[rowtemp-1][coltemp] = mat[rowtemp][colread];
coltemp++;
}
}
You are looping twice through the columns, once for coltemp == 0
, and then in the inner loop, coltemp
is incremented order-1
times, so the inner loop runs a second time with coltemp == order-1
at the start. Then coltemp
is again incremented multiple times in the loop, and you're writing out of bounds of the allocated memory.
The outer loop should be removed, coltemp = 0;
and the inner loop are what you need.
pow(-1,column))
is not a good way to determine a sign.
(1 - 2*(column & 1))
is faster than a call to pow
.
Finally, in main
for(row=0; row<N; row++)
{
printf("| ");
for(column=0; column<N; column++)
{
fscanf(input,"%lf ", &matrix[row][column]);
printf("%g ", matrix[row][column]);
}
if(row != (N/2))
{
printf("|\n");
}
else
{
printf("|= %lf \n", det(matrix, N) );
}
}
You are printing the determinant at row N/2
, which looks nice, but at that time, you have not yet scanned in the entire matrix, so rows N/2 + 1
to N-1
contain uninitialised data, which is not unlikely to be all zeros. If you change the if (row != N/2)
to if (row != N-1)
, it will work, however, the proper way to handle it is to separate the scanning of the matrix from the computation and the printing. These are all independent operations that should be handled in their own separate functions.
Upvotes: 2