jest jakiś sposób, aby zabezpieczyć się przed dzieleniem przez zero? chodzi mi o np takie przypadki:
1 1 1 2 2 2 1 1 0
1 1 1 2 2 2 1 1 2
1 1 1 2 2 2 2 3 1
jest jakiś sposób, aby zabezpieczyć się przed dzieleniem przez zero? chodzi mi o np takie przypadki:
1 1 1 2 2 2 1 1 0
1 1 1 2 2 2 1 1 2
1 1 1 2 2 2 2 3 1
Przypadek 1 i 2 dają dają wartość końcową zero więc to jest bezsensu.
Przypadek 3.
algorytm powinien działać tak:
1 1 0 1 1 0 1 0 1
1 1 2 0 0 2 --> 0 1 1 * -1
2 3 1 0 1 1 0 0 2
Czyli jeśli trafi ci się taki problem to zamieniasz miejscami wiersze lub kolumny zmieniając równocześnie znak wyniku (lub jednego wiersza albo kolumny).
nie do końca jest bez sensu, bo robiąc eliminację gaussa jakiejkolwiek macierzy o tych samych elementach mam dzielenie przez zero. w dwóch pierwszych przypadkach można oczywiście sprawdzić czy jakiś wiersz bądź kolumna składają się z takich samych elementów, ale nie rozwiąże do przypadku trzeciego(a szukam jakiejś uniwersalnej metody). mam taki oto kod i nie bardzo mam pomysł gdzie miałaby się ta zamiana kolumn odbywać (stosuję ją tylko dla pierwszego wiersza, a dla reszty jakoś nie ogarniam):
float wyznacznik(macierz_t *macierz, int glowny)
{
float det;
int i,j,k,x,ctr=0;
macierz_t *macierz1;
float niezerowy;
macierz1=kopiuj_macierz(macierz);
niezerowy=macierz1->macierz[0][0];
for(i=0;i<macierz1->lk;i++) /*zlicza niezerowe elementy pierwszego wiersza*/
{
if(macierz1->macierz[0][i]!=0)
ctr++;
}
if(ctr==0 && glowny==0) /*jeśli same zera w pierwszym wierszu*/
{ /*i jest to pierwsze wywołanie funkcji*/
printf("Macierz nieodwracalna(wyznacznik 0)");
exit(EXIT_FAILURE);
}
if(macierz1->lw==1)
{
return(macierz1->macierz[0][0]); /*zwraca element, jeśli macierz jest 1x1*/
}
else
{
if(macierz1->macierz[0][0]!=0) /*jeśli pierwszy el mzcierzy jest różny od 0*/
{
for(i=0;i<macierz1->lw-1;i++) /*wykorzystując metodę eliminacji gaussa zeruje elementy*/
{ /*pod przekątną diagonalną*/
for(j=i+1;j<macierz1->lw;j++)
{
for(k=i+1;k<macierz1->lk;k++)
macierz1->macierz[j][k]-=(macierz1->macierz[j][i]/macierz1->macierz[i][i])*macierz1->macierz[i][k];
}
}
det=1;
for(i=0;i<macierz1->lw;i++) det*=macierz1->macierz[i][i]; /*wyznacznik macierzy równy jest iloczynowi elementów*/
return(det); /*na przekątnej diagonalnej*/
}
else /*jeśli pierszy element jest równy 0*/
{
for(j=0;j<macierz1->lk;j++) /*szuka niezerowego elementu w pierwszym wierszu*/
{
if(macierz1->macierz[0][j]!=0)
{
niezerowy=macierz1->macierz[0][j];
x=j; /*przypisuje numer kolumny zmiennej x*/
}
}
for(i=0;i<macierz1->lw;i++) /*zamienia kolumny*/
{
niezerowy=macierz1->macierz[i][0];
macierz1->macierz[i][0]=macierz1->macierz[i][x];
macierz1->macierz[i][x]=niezerowy;
}
for(i=0;i<macierz1->lw-1;i++) /*wykorzystując metodę eliminacji gaussa zeruje elementy*/
{ /*pod przekątną diagonalną*/
for(j=i+1;j<macierz1->lw;j++)
{
for(k=i+1;k<macierz1->lk;k++)
macierz1->macierz[j][k]-=(macierz1->macierz[j][i]/macierz1->macierz[i][i])*macierz1->macierz[i][k];
}
}
det=1; /*wyznacznik macierzy równy jest iloczynowi elementów*/
for(i=0;i<macierz1->lw;i++) det*=macierz1->macierz[i][i]; /*na przekątnej diagonalnej*/
return(-det); /*zamieniliśmy jedną kolumnę, więc zmieniamy znak ma*/
} /*przeciwny*/
}
}
może popatrz jak to się robi w "Numerical Recipes".
A tu masz moją wersję. Powinno być ok, ale lepiej sprawdź czy gdzieś się nie walnąłem (bo tego nie testowałem).
double wyznacznik(macierz_t *macierz) {
assert(macierz->lw == macierz->lk); // musi być kwadratowa
if(macierz->lw==1) {
return macierz1->macierz[0][0];
}
if(macierz->lw==2) {
return macierz1->macierz[0][0] * macierz1->macierz[1][1] - macierz1->macierz[1][0] * macierz1->macierz[0][1];
}
macierz_t *m = kopiuj_macierz(macierz);
int n = m->lw;
double det = 1.0;
for(int i=0; i<n; ++i) {
if(m->macierz[i][i] == 0.0) {
int j;
for(j=i+1; j<n; ++j) // znajdź lepszy wiersz
if(m->macierz[j][i]!=0) {
double *tmp = m->macierz[i];
m->macierz[i] = m->macierz[j]
m->macierz[j] = tmp;
det = -det;
break;
}
if(j==n) { // nie znaleziono zastępstwa więc wynik końcowy to zero
usunMacierz(m);
return 0;
}
}
for(int j=i+1;j<n; ++j) {
// odejmuj od j-tego wiersza odpowiednią wielokrotność i-tego wiersza
if(m->macierz[j][i] == 0.0)
continue;
double factor = m->macierz[j][i]/m->macierz[i][i];
m->macierz[j][i] = 0.0; // w sumie ta linijka potrzebna jest tylko podczas debugowania, żeby widzieć, że robi się ok
for(int k=i+1;j<n; ++j)
m->macierz[j][k]-=factor * m->macierz[i][k];
}
} // for i
for(int i=0;i<n; ++i)
det *= m->macierz[i][i];
usunMacierz(m);
return det;
}
Ok, wielkie dzięki, bo z tej książki niewiele ogarniałem. Zaraz przetestuję
hey, mam takie samo zadanie do zrobienia tylko nie wiem jak zacząć, a to nie bardzo dziala możecie przesłać cały kod bardzo bym była wdzięczna za pomoc
eliminacja Gaussa-Crouta omija problem z zerami.