Metoda Gaussa, różne wyniki przy różnych sposobach wyboru elementu

0

Witam,
Mam problem z projektem dotyczącym obliczania układów liniowych przy pomocy metody Gaussa.
W projekcie mamy utworzyć 4 różne funkcje obliczające wartości niewiadomych różniące się sposobem wybrania elementu stojącym w lewym górnym rogu (chodzi o to żeby np. nigdy nie stało tam zero). Jednak w zależności jaką funkcję wybiorę w niektórych wypadkach otrzymuje różne wyniki i nie wiem co jest tego przyczyną.

Przykładowe dane w których widać ten problem:

ilość niewiadomych: 3

macierz:
2 3 -4 9
1 2 -2 7
4 -2 5 -5

#include <iostream>
#include <cmath>


using namespace std;
void wczytywanie_macierzy(float **macierz,int rozmiar)
{
    for (int i=0; i<rozmiar; i++)
    {
        cout<<"\nPodaj " << i+1 << " wiersz:\n";
        for (int j=0; j<rozmiar+1; j++)
        {
            cin>>macierz[i][j];
        }
    }
}

void wyswietl(float **macierz,int rozmiar)
{
    for (int i=0; i<rozmiar; i++)
    {
        cout<<endl;
        for (int j=0; j<rozmiar+1; j++)
        {
            cout<<macierz[i][j]<<"   ";
        }
    }
}

void Gauss(float **macierz,int rozmiar, int a)
{
    float w;
    for(int i=a+1; i<rozmiar; i++)
    {
         w=macierz[i][a]/macierz[a][a];

        for(int j=a; j<rozmiar+i; j++)
        {
            macierz[i][j]-=w*macierz[a][j];
        }
    }
}

void wyznaczanie_wartosci(float *wyniki,float **macierz,int rozmiar,bool &flaga)
{
    wyniki[rozmiar-1]=macierz[rozmiar-1][rozmiar] / macierz[rozmiar-1][rozmiar-1];
    float suma;

    for(int i=rozmiar-2; i>=0 && flaga==1; i--)
    {
        suma=0;
        for(int j=rozmiar-1; j>i; j--)
        {
            suma+=wyniki[j]*macierz[i][j];
        }
        if(macierz[i][i]!=0)
        {
            wyniki[i]=(macierz[i][rozmiar]-suma)/macierz[i][i];
            if(fabs(wyniki[i]<0.0000001)) wyniki[i]=0;
        }
        else
        {
            flaga=0;
        }

    }
}

void redukcja_bledow(float **macierz,int rozmiar)
{
    for (int i=0; i<rozmiar; i++)
    {
        for (int j=0; j<rozmiar+1; j++) //tutaj zmiana
        {
            if(fabs(macierz[i][j]) < 0.0000001)
                macierz[i][j]=0;
        }
    }
}

void wiersz_swap(float **macierz,int rozmiar, int a, int b)
{
    for(int i=0; i<rozmiar+1; i++)
    {
        swap(macierz[a][i],macierz[b][i]);
    }
}

void kolumna_swap(float **macierz,int rozmiar, int a, int b,int *kolejnosc)
{
    for(int i=0; i<rozmiar; i++)
    {
        swap(macierz[i][a],macierz[i][b]);

    }
    swap(kolejnosc[a],kolejnosc[b]);
}

void najwiekszy_w_kolumnie(float **macierz,int rozmiar, int &najwiekszyKolumna, int a)
{
    for(int i=a; i<rozmiar; i++)
    {
        if(fabs(macierz[najwiekszyKolumna][a]) < fabs(macierz[i][a]))  najwiekszyKolumna=i;


    }
}

void najwiekszy_w_wierszu(float **macierz,int rozmiar, int &najwiekszyWiersz, int a)
{
    for(int i=a; i<rozmiar; i++)
    {
        if(fabs(macierz[a][najwiekszyWiersz]) < fabs(macierz[a][i]))  najwiekszyWiersz=i;


    }
}

void najwiekszy_w_macierzy(float **macierz,int rozmiar, int &najwiekszyWiersz,int &najwiekszyKolumna, int a)
{
    for(int i=a; i<rozmiar; i++)
    {
        for(int j=a; j<rozmiar; j++)
        {
            if(fabs(macierz[najwiekszyKolumna][najwiekszyWiersz])<fabs(macierz[i][j]))
            {
                najwiekszyKolumna=i;
                najwiekszyWiersz=j;
            }
        }
    }
}

void wyswietl_wyniki(float wyniki[],int rozmiar)    //w przypadku podstawowego Gaussai w przypadku szukania w kolumnie
{
    cout<<"\nWyniki:";
    for(int i=0; i<rozmiar; i++)
    {
        cout<<"\nX"<<i<<"   ="<<wyniki[i];
    }
    cout<<endl;
}

void wyswietl_kolejnosc(float wyniki[],int kolejnosc[],int rozmiar)
{
    cout<<"\nWyniki:";
    for(int i=0; i<rozmiar; i++)
    {
        cout<<"\nX"<<kolejnosc[i]<<"   ="<<wyniki[i];
    }
}

void Gauss_podstawowy(float **macierz,int rozmiar, float *wyniki)
{
    bool flaga=1;
    for(int i=0; i<rozmiar; i++)
    {
        Gauss(macierz,rozmiar,i);
        redukcja_bledow(macierz,rozmiar);
    }
    wyznaczanie_wartosci(wyniki,macierz,rozmiar,flaga);
    if(flaga==1)
    {
        wyswietl(macierz,rozmiar);
        wyswietl_wyniki(wyniki,rozmiar);
    }
    else
    {
        cout<<"Nie mozna obliczyc wartosci niewiadomych ta metoda";
    }
}

void Gauss_w_wierszu (float **macierz,int rozmiar, float *wyniki)  //w zrodle jest to "w kolumnie"
{
    int maksI;
    bool flaga=1;
    for(int i=0; i<rozmiar; i++)
    {

        maksI=i;
        najwiekszy_w_kolumnie(macierz,rozmiar,maksI,i);
        wiersz_swap(macierz,rozmiar,maksI,i);
        redukcja_bledow(macierz,rozmiar);
        Gauss(macierz,rozmiar,i);
        redukcja_bledow(macierz,rozmiar);

    }
    wyznaczanie_wartosci(wyniki,macierz,rozmiar,flaga);
    if(flaga==1)
    {
        wyswietl(macierz,rozmiar);
        wyswietl_wyniki(wyniki,rozmiar);
    }
    else
    {
        cout<<"Nie mozna obliczyc wartosci niewiadomych ta metoda";
    }

}

void Gauss_w_kolumnie( float **macierz,int rozmiar, float *wyniki, int *kolejnosc)
{
    int maksJ;
    bool flaga=1;

    for(int i=0; i<rozmiar; i++)
    {

        maksJ=i;
        najwiekszy_w_wierszu(macierz,rozmiar,maksJ,i);
        kolumna_swap(macierz,rozmiar,maksJ,i,kolejnosc);
        redukcja_bledow(macierz,rozmiar);
        Gauss(macierz,rozmiar,i);
        wyswietl(macierz,rozmiar);
        redukcja_bledow(macierz,rozmiar);

    }

    wyznaczanie_wartosci(wyniki,macierz,rozmiar,flaga);
    if(flaga==1)
    {
        wyswietl(macierz,rozmiar);
        wyswietl_kolejnosc(wyniki,kolejnosc,rozmiar);
    }
    else
    {
        cout<<"Nie mozna obliczyc wartosci niewiadomych ta metoda";
    }
}

void Gauss_pelny(float **macierz,int rozmiar, float *wyniki, int *kolejnosc)
{
    int maksJ;
    int maksI;
    bool flaga=1;
    for(int i=0; i<rozmiar; i++)
    {
        maksJ=i;
        maksI=i;
        najwiekszy_w_macierzy(macierz,rozmiar,maksJ,maksI,i);
        wiersz_swap(macierz,rozmiar,maksI,i);
        kolumna_swap(macierz,rozmiar,maksJ,i,kolejnosc);
        Gauss(macierz,rozmiar,i);
        redukcja_bledow(macierz,rozmiar);

    }

    wyznaczanie_wartosci(wyniki,macierz,rozmiar,flaga);
    if(flaga==1)
    {
        wyswietl(macierz,rozmiar);
        wyswietl_kolejnosc(wyniki,kolejnosc,rozmiar);
    }
    else
    {
        cout<<"Nie mozna obliczyc wartosci niewiadomych ta metoda";
    }

}

void kolejnosc_zerowanie(int *kolejnosc,int rozmiar)
{
    for(int i=0; i<rozmiar; i++)
    {
        kolejnosc[i]=i+1;
    }
}

void przepisanie(float **skad, float **dokad,int rozmiar)
{
    for (int i=0; i<rozmiar; i++)
    {
        for (int j=0; j<rozmiar+1; j++)
        {
            dokad[i][j]=skad[i][j];
        }
    }
}


int main()
{
    int n;
    int wybor;
    bool warunek=1;

    cout << "Podaj ilosc zmiennych: ";
    cin >> n;

    int kolejnosc[n];
    float wyniki[n];

    float **tab = new float *[n];
    for(int i=0; i<n; i++)
    {
        tab[i] = new float [n+1];
    }

    wczytywanie_macierzy(tab,n);

    float **badana=new float *[n];
    for(int i=0; i<n; i++)
    {
        badana[i] = new float [n+1];
    }

    przepisanie(tab,badana,n);

    while(warunek==1)
    {
        cout<<"\n1.Podstawowy:\n21.Wybor w wierszu\n22.Wybor w kolumnie \n3.Pelny Gauss\n4.Wyjscie\n";
        cin>>wybor;
        switch(wybor)
        {
        case 1:
        {
            przepisanie(tab,badana,n);
            Gauss_podstawowy(badana,n,wyniki);
            break;
        }
        case 21:
        {
            przepisanie(tab,badana,n);
            Gauss_w_wierszu(badana,n,wyniki);
            break;
        }
        case 22:
        {
            przepisanie(tab,badana,n);
            kolejnosc_zerowanie(kolejnosc,n);
            Gauss_w_kolumnie(badana,n,wyniki,kolejnosc);
            break;
        }
        case 3:
        {
            przepisanie(tab,badana,n);
            kolejnosc_zerowanie(kolejnosc,n);
            Gauss_pelny(badana,n,wyniki,kolejnosc);
            break;
        }
        case 4:
        {
            cout<<"\n*******************************************************\nKONIEC\n";
            warunek=0;
        }

        default:
        {
            cout<<"\nNieprawidlowa funkcja\n";
            break;
        }
        }

    }

    for(int i=0; i<n; i++)
    {
        delete tab[i];
    }
    delete tab;

    for(int i=0; i<n; i++)
    {
        delete badana[i];
    }
    delete badana;

    return 0;
}


0

Nie wgłębiałem się w samą metodę, ale

    cin >> n;

    int kolejnosc[n];
    float wyniki[n];

To nie jest C++, C++ nie ma VLA.


    float **badana=new float *[n];
     // ...
    delete badana;

UB, zamiast się tak męczyć: https://dsp.krzaq.cc/post/98/prosty-widok-na-macierz-2d-w-cpp/

1

Też się nie wgłebiałem, ale znając metodę Gaussa, to wyniki mogą być minimalne inne (błąd zmiennoprzecinkowy), dla różnego wyboru elementu podstawowego. Policzyłeś to na kartce? Wiesz co powinno wyjść? Dla których sposobów wychodzi dobrze, dla których źle? Nic nie napisałeś...

0
koszalek-opalek napisał(a):

Też się nie wgłebiałem, ale znając metodę Gaussa, to wyniki mogą być minimalne inne (błąd zmiennoprzecinkowy), dla różnego wyboru elementu podstawowego. Policzyłeś to na kartce? Wiesz co powinno wyjść? Dla których sposobów wychodzi dobrze, dla których źle? Nic nie napisałeś...

już znalazłem błąd:
W jednej z funkcji przy porównaniu wartości bezwględnej z 0.000001 tak naprawdę nie porównywałem wartości bezwględnej a brałem moduł z porównania( a co ciekawe kompilator to przepuscił),
i kiedy tylko miałem wartość mniejszą od zera to była ona zamieniana na 0 i stad złe wyniki.

Ale dziękuje za zainteresowanie

if(macierz[i][i]!=0)
        {
            wyniki[i]=(macierz[i][rozmiar]-suma)/macierz[i][i];
            if(fabs(wyniki[i]<0.0000001)) wyniki[i]=0;
        }
0
Aquater napisał(a):

W jednej z funkcji przy porównaniu wartości bezwględnej z 0.000001 tak naprawdę nie porównywałem wartości bezwględnej a brałem moduł z porównania( a co ciekawe kompilator to przepuscił),

Przepuścił, bo bool ma wartośc liczbową (0 lub 1) a moduł z tego jest przecież obliczalny... Nie ma tu noc dziwnego.

1 użytkowników online, w tym zalogowanych: 0, gości: 1