Вычислить определитель матрицы с частичным поворотом Гаусса в C

Я пытаюсь создать простое консольное приложение на C, которое будет вычислять определитель матрицы, используя метод исключения частичного поворота Гаусса. У меня есть две проблемы: - кто-то сказал мне, что есть определенные матрицы, которые не работают с этим методом (математически говоря), после прочтения статей в Google я не мог найти, что это за особый случай - после Много тестов я обнаружил, что моя программа не работает для некоторых матриц, после 2 дней "траты времени" на редактирование и отмену я не смог найти проблему.

Любые улучшения приветствуются. Я только начинаю с C.

#include<stdio.h>
#include<cstdlib>
#include<math.h>
#include<conio.h>
#include<windows.h>

// calculate biggest element on column

int indice_max(int dim, int col, float coloana[20][20]) {

    float max = 0;
    int indice;

    for(int i = 1; i <= dim; i++)
        if(fabs(max) < fabs(coloana[i][col])) {
            max = coloana[i][col];
            indice = i;
        }

    return indice;

}

// permute 2 lines

void permutare_linie(int linie1, int linie2, int dim, float matrice[20][20]) {

    float aux;

    for(int i = 1; i <= dim; i++) {
        aux = matrice[linie1][i];
        matrice[linie1][i] = matrice[linie2][i];
        matrice[linie2][i] = aux;
    }

}

// print matrix

void afisare_matrice(int dimensiune, float matrice[20][20], int lpiv) {

    for(int i = 1; i<= dimensiune; i++) {
        for(int j = 1; j <= dimensiune; j++) {
            if(i == lpiv)
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), BACKGROUND_GREEN);
            else
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );
            printf("%4.2f ", matrice[i][j]);
        }
        printf("\n");
    }

}


void main(void) {

    float matrice[20][20];
    int dimensiune ;
    float rezultat = 1;
    float pivot;
    int lpiv;
    int cpiv;
    int optiune;
    while(1) {

        // MENU

        printf("ALEGET OPTIUNEA:\n");
        printf("1) Calculate matrix determinant\n");
        printf("2) Exit\n");
        scanf("%d", &optiune);

        if(optiune == 1) {

            // Read determinant dimension

            printf("Matrix dimension:");
            scanf("%d", &dimensiune);

            // Read determinant

            for(int i = 1; i <= dimensiune; i++)
                for(int j = 1; j <= dimensiune; j++) {
                    printf("M[%d][%d]=", i, j);
                    scanf("%f", &matrice[i][j]);
            }

            // pivot initial coords

            lpiv = 1;
            cpiv = 1;

            printf("\n----- Entered Matrix -----\n\n");
            afisare_matrice(dimensiune, matrice, 0);
            printf("\n");

            for(int pas = 1; pas <= dimensiune - 1; pas++) {

                if(fabs(matrice[lpiv][cpiv]) > fabs(matrice[indice_max(dimensiune, cpiv, matrice)][cpiv])) {
                    permutare_linie(lpiv, indice_max(dimensiune, cpiv, matrice), dimensiune, matrice);
                    rezultat = -(rezultat);
                }

                pivot = matrice[lpiv][cpiv];


                for(int inm = 1; inm <= dimensiune; inm++) {
                    matrice[lpiv][inm] = matrice[lpiv][inm] / pivot;
                }

                rezultat *= fabs(pivot);

                // transform matrix to a superior triangular 
                for(int l = lpiv+1; l <= dimensiune; l++)
                    for(int c=cpiv+1; c <= dimensiune; c++) {
                        matrice[l][c] -= matrice[l][cpiv] * matrice[lpiv][c] / matrice[lpiv][cpiv];
                    }

                for(int i = lpiv + 1; i <= dimensiune; i++)
                    matrice[i][cpiv] = 0;
                // afisam rezultat / pas

                printf("----- Step %d -----\n\n", pas);
                afisare_matrice(dimensiune, matrice, lpiv);
                printf("\nResult after step %d : %4.2f\n\n", pas, rezultat);
                lpiv++;
                cpiv++;
            }

            // final result

            rezultat = rezultat * matrice[dimensiune][dimensiune];
            printf("----- REZULTAT FINAL -----\n\n");
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
            printf("Rezultat = %4.2f\nRezultat rotunjit:%4.0f\n\n", rezultat, floorf(rezultat * 100 +  0.5) / 100);
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE );

        }
        else {
            exit(0);
        }
    }
}

person BebliucGeorge    schedule 19.10.2011    source источник
comment
Что ж, зайдите в библиотеку и найдите книгу о численных методах, таких как Numerical Methods, Burden & Faires, если я не ошибаюсь, и посмотрите их реализацию на C для исключения Гаусса, HTH   -  person Umut Tabak    schedule 19.10.2011
comment
Это объясняется в статье в Википедии. Необратимая квадратная матрица называется сингулярной или вырожденной. Квадратная матрица сингулярна тогда и только тогда, когда ее определитель равен 0. Сингулярные матрицы редки в том смысле, что если вы выберете случайную квадратную матрицу, она почти наверняка не будет сингулярной.   -  person user786653    schedule 19.10.2011
comment
Не нужно даже в библиотеку! Ознакомьтесь с главой 2: nrbook.com/a/bookcpdf.php   -  person John    schedule 19.10.2011
comment
@ user786653 В вашем объяснении говорится, что матрица необратима. Сингулярная матрица - это когда ее определитель равен 0, но мне нужно вычислить определитель, чтобы увидеть, равен ли он 0 или нет. В сети есть примеры кода для этой процедуры, но они не выполняют те же действия, что и мой университетский профессор.   -  person BebliucGeorge    schedule 19.10.2011
comment
См. Ответ @anatolygs, сингулярная матрица в какой-то момент будет иметь нулевой столбец, нет необходимости явно вычислять определитель.   -  person user786653    schedule 19.10.2011


Ответы (1)


Ваш код делает некоторое деление:

matrice[lpiv][inm] = matrice[lpiv][inm] / pivot;

Если произойдет деление на ноль, произойдет ошибка. Думаю, это произойдет с нулевой матрицей.

Кажется, что ваш код на самом деле пытается перевернуть матрицу, а не просто вычислить определитель.

person anatolyg    schedule 19.10.2011
comment
Конечно, я думал, что один из элементов на диагонали будет равен 0, но не думал, что они могут быть 0 после операций, сделанных для преобразования матрицы в матрицу высшего треугольника. Спасибо. Думаю, я нашел и другую проблему. Я ищу максимальный элемент во всем столбце, а не только под опорной точкой. - person BebliucGeorge; 19.10.2011