[C] Dwuwymiarowe tablice i wyznacznik

soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Tak sie sklada, ze wlaczalem twoj program
Nie uwazam sie za jakiegos profesjonaliste, tylko zapisuje tutaj swoje uwagi, ktore pozniej moga sie wielu osobom przydac. Programuje juz dobre kilka lat w C/C++ znam Jave, Pascala oraz asemblera pod procesory z rodziny x86, takze doswiadczenie mam i wiem co to rzutowanie.

Pytalem o to wyrazenie, gdyz nie jest ono do konca poprawne. Tzn. wywolujac operator porownania na dwoch ROZNYCH typach liczbowych jeden musi zostac skonwertowany do drugiego. W twoim przypadku zmienna typu int zostanie skonwertowana do typu float. I tutaj jest haczyk: liczby typu float maja ograniczona dokladnosc. Wynika stad pewna ich wada - nie zawsze mozna do ich porownywania uzywac operatora ==. Aby sie o tym przekonac wpisz w swoim programie wartosc np. 15.0000001 i zobacz jak sie zachowa. Wypluje TAK (jesli pracujesz na procesorze 32 bitowym), choc powinien podac NIE. Podkreslam - nie jest to jakas tam zlosliwosc, tylko post poparty doswiadczeniem w programowaniu.


Co do void main() - rob jak chcesz. W kazdym badz razie jak ci przyjdzie na studiach (jesli idziesz na jakies lepsze zwiazane z informatyka) napisac program zgodny ze standardem ANSI C i roznymi flagami typu -Wall -pedantic to sie zdziwisz ile masz ostrzezen/bledow w swoim kodzie. Co do samych nieomylnych kompilatorow, to gcc ktorego ja uzywam (standardowy w srodowisku Code::Blocks) nie jest taki nieomylny. Mozna w prosty sposob zamienic wartosc stalej w programie, co jest rzecza raczej nieporzadana... Dlatego radze uwazac na to, co sie pisze...

Pozdrawiam.


Co do wyznacznika - nie pamietam co to byla ta macierz Jordana, wiec za bardzo nie pomoge. Pamietam tylko, ze mozna macierz sprowadzic do postaci macierzy trojkatnej (eliminacja Gaussa) a pozniej juz wyznacznik bardzo latwo sie liczy.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Panowie! Przestańcie się kłócić, który ma rację, bo to i tak mnie jako początkującemu nie pomaga w rozwiązaniu tego zadania. Bardzo bym prosiłbym o dalszą pomoc przy tych wyznacznikach - pytanie a propo ich napisałem w swoim powyższym poście.

No to jeśli chodzi o trójkątną macierz to mniej więcej o to mi chodziło = przecież macierz Jordana (składająca się z bloków z wartościami własnymi na głównej przekątnej, i bloki uzupełniane jedynkami w zależności od rozmiaru bloku) też jest trójkątna - tylko specyficzna.

Tu masz definicję macierzy Jordana - chyba oto samo nam chodziło nieprawdaż soku11?



Może być ta trójkątna - tylko powiedz mi jak to napisać?
Ostatnio zmieniony 28 mar 2009, o 19:33 przez Nighthunter24, łącznie zmieniany 1 raz.
6hokage
Użytkownik
Użytkownik
Posty: 268
Rejestracja: 24 mar 2009, o 13:06
Płeć: Mężczyzna
Podziękował: 1 raz
Pomógł: 35 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: 6hokage »

A to spoko, cofam swoje uszczypliwości, sądziłem, że jesteś wielkim mądrzyckim, który nawet nie stara się zrozumieć drugiej osoby, a ją krytykuje. Ale jednak tak nie jest. Na przyszłość jednak radzę pisać konkretniej bo słowa "chyba nie wiesz co robisz, co ma oznaczać linijka if(b==a)" są bardzo ogólnikowe i tak naprawdę nie wiadomo czy coś nie pasuje Ci w konstrukcji, czy może jest ona nieprawidłowa w kontekście całego programu. Słowem gdybyś napisał od razu, to co w ostatnim poście to nie byłoby afery. Także pozdrawiam.
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Czytaj dokladnie moje posty - napisalem, ze wypelniajac tablice 3x3 w funkcji zewnetrznej uzywasz wskaznikow, tylko nie masz tam znaczka *. Dlatego wlasnie zmienia sie zawartosc tablicy w main!

Co do metody, to dopisalem w tym dlugim poscie na koncu. Moge tylko dodac, ze o liczeniu wyznacznikow w programowaniu jest sporo tematow w internecie...

Pozdrawiam.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

No dobrze - napisałeś że eliminacją Gaussa można ją sprowadzić do macierzy trójkątnej - tylko jak taką funkcję napisać z użyciem wskaźników w sensie *zmienna (bo to mi chodzi - i tak samo to z treści wynika : inni którzy wcześniej skończyli - prowadzący zajęcia powiedział że to nie jest koniec programu - bo brakuje zastosowania wskaźników - czyli *zmienna). Przynajmniej tej metody nie znalazłem ze wskaźnikami (*zmienna). Może ja dla przykładu podam jak wyobrażałem sobie użycie tych wskaźników (mój poprzedni program z laboratoriów który napisałem z zastosowanie wskaźników - jest po angielsku) :

Kod: Zaznacz cały

#include<stdio.h>
#include<time.h>
#include<stdlib.h>

void bsort(int *a); /*function bubble sort*/

int main()
{
  int tableA[20], tableB[20], tableC[20];
  int i;
  
  srand(time(0)); /*for every running of the program the seed 
  of pseudorandom numbers is different*/
  
  for(i=0; i<20; i++) 
  {
  	tableA[i]=rand()%1001;
  	tableB[i]=rand()%1001; /*filling in elements of the tableA and tableB with
    random numbers <0,1000>*/
  	tableC[i]=tableA[i]+tableB[i]; /*filling in elements of the tableC is the
  	result of addition values of elements of tableA and tableB*/
  }

  bsort(tableC); /*function buble sort call*/
  printf("TableA :	TableB :	TableC :
");
  for(i=0; i<20; i++) /*writing elements of tableA, tableB, tableC*/
  {
  	printf("%d		%d		%d
", tableA[i], tableB[i], tableC[i]);
  }
  
  return 0;
}

void bsort(int *a) /*prototype of function bubble sort*/
{
  int i, j, now; /*now - auxiliary variable*/
  
  /*bubble sorting of elements of array in decreasing order*/
  for(i=0; i<20; i++) 
  {
  	for(j=0; j<20; j++)
  	{
      if(*(a+j)<*(a+j+1)) 
	  /*the comparison of adjacent elements of array*/
      {
  	    now=*(a+j+1); 
        *(a+j+1)=*(a+j); /*shifting round the adjacent elements of array*/
        *(a+j)=now; 
      }   
  	}
  }
}
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

No to teraz zmien sobie ta funkcje, na:

Kod: Zaznacz cały

void bsort(int a[20]);
Niezauwazysz ZADNEJ roznicy. Jedyna roznica, to zapis funkcji. Jednak przekazywanie danych zachodzi dokladnie tak samo.

Pozdrawiam.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Nie odpowiedziałeś na moje pytanie. Ja to wiem - bo robiłem ten program dwoma metodami - poprzez pointer i poprzez zmienną array - i też to zauważyłem że przekazywanie jest takie same, tylko inni zapis - i to samo właśnie proszę ciebie żebyś mi pomógł w przypadku dwuwymiarowych tablic - bo poprostu nie wiem jak przez pointer (wskaźnik = *zmienna; tak jak to napisałem w moim przykładowym programie) policzyć ich wyznaczniki (bo właśnie z tym mam problem), bo tak to w tradycyjny poprzez array(tablicę) potrafię to zrobić - a mnie potrzeba przekazać je przez wskaźnik (czytaj *zmienna). Bardzo bardzo bym cię prosił soku11!
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

Kod: Zaznacz cały

#include <stdio.h>

void funArray2D(int* tab,int dim)
{
  #define _tab(i,j) tab[i+j*dim]
  printf("%d%d%d
",_tab(0,0),_tab(1,0),_tab(2,0));
  printf("%d%d%d
",_tab(0,1),_tab(1,1),_tab(2,1));
  printf("%d%d%d
",_tab(0,2),_tab(1,2),_tab(2,2));
  #undef _tab

  printf("

");
  /* lub poprostu tak */
  printf("%d%d%d
",tab[0],tab[1],tab[2]);
  printf("%d%d%d
",tab[3],tab[4],tab[5]);
  printf("%d%d%d
",tab[6],tab[7],tab[8]);
}

int main()
{
  int tab[3][3]={
    {0,1,2},
    {2,3,4},
    {4,5,6}
    };

  funArray2D(tab[0],3);
  return 0;
}
Wielowymiarowe tablice statyczne sa allokowane na stosie jako zwykle tablice, tak wiec kazdy element tablicy wielowymiarowej lezy po kolei na stosie. Mozna wiec sie bez problemu do tych elementow odwolywac jak do tablicy jednowymiarowej. Napisalem przykladowa funkcje, ktora opisuje jak korzystac z takiego czegos. Mozna oczywiscie duzo latwiej, jednak wtedy trzeba by bylo wykorzystac dynamiczna allokacje pamieci. Dzieki niej mozna by bylo napisac funkcje:

Kod: Zaznacz cały

void fun(int** tab);
I odwolywac sie do elementow tablicy w ten sposob:

Kod: Zaznacz cały

tab[i][j];
Pozdrawiam.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Mój kod programu (sorry że po angielsku - ale myślałem że już mi się uda samemu go dalej napisać - a jednak poległem) :

Kod: Zaznacz cały

#include<stdio.h>

void Fill(int tab[3][3]); /*function Fill*/
void Print(int tab[3][3]); /*function Print*/
int DetLaPlace(int **tab); /*function DetLaPlace*/
void Minor(int c1, int tab1[3][3], int tab2[2][2]); /*function Minor*/
int Power(int c1); /*function Power*/

int main()
{
  int i, j, A[3][3], B[3][3], C[3][3];
  
  
  Fill(A);
  Fill(B);
  
  printf("The matrix A consists of the following elements : \n");
  Print(A); /*function Print call for matrix A*/
  
  printf("The matrix B consists of the following elements : \n");
  Print(B); /*function Print call for matrix B*/
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      C[i][j]=A[i][j]+B[i][j]; /*filling in elements of the matrix C is the
  	result of addition values of elements of matix A and matrix B*/
    }
  }
  
  printf("The matrix C consists of the following elements : \n");
  printf("\n");
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      printf("a[%d][%d] = ", i, j); /*a[i][j] denotes an element of the matrix*/
      printf("%d", C[i][j]); /*printing the elements of matrix C*/
      printf("\n");	
    }
  }
  
  printf("The value of the determinant of the matrix A = %d\n", DetLaPlace(A));
  printf("The value of the determinant of the matrix B = %d\n", DetLaPlace(B));
  printf("The value of the determinant of the matrix C = %d\n", DetLaPlace(C));
  
  return 0;
}

void Fill(int tab[3][3]) /*prototype of function Fill*/
{
  int i, j;
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      do
      {
        printf("Write integer number <0,10> for a[%d][%d] = ", i, j);
        scanf("%d", &tab[i][j]); /*reading of elements of matrix which are
		written by user*/   
      }
      while(tab[i][j]<0 || tab[i][j]>10); 
	  /*the condition of filling in elements of matrix with numbers <0,10>*/
    }
  }
  
  printf("\n");
}

void Print(int tab[3][3]) /*prototype of function Print*/
{
  int i, j;
  
  printf("\n");
     
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      printf("a[%d][%d] = ", i, j);
      printf("%d",tab[i][j]); /*printing elements of the matrix*/ 
      printf("\n");	
    }
  }
  
  printf("\n");
}

/*First method to calculate determinant of the matrix - using 
LaPlace formula*/
int DetLaPlace(int **tab) /*prototype of function DetLaPlace*/
{
  int j, det=0; /*j - the column (with respect to this column we 
  calculate the determinant of the matrix; 
  minor of the matrix - obtained by the*/
       
  for(j=0; j<3; c1++)
  {
    Minor(c1, tab1, tab2); /*function Minor call*/
    det = det + Power(c1) * tab[0][j] * DetLaPlace(tab2); 
  }
  
  return det;
}

void Minor(int j, int tab1[3][3], int tab2[2][2]) /*prototype function Minor*/
{
int k, l;
    for(k=0; k<2; k++)
    {
      for(l=0; l<c1; l++)
      {
        tab2[k][l] = tab1[k+1][l];
      }
      for(l=j+1; l<3; l++)
      {
        tab2[k][l-1] = tab1[k+1][l];        
      }
    }
}

int Power(int j) /*prototype function Power*/
{
/*calculating the power (-1)^(i+j)*/	
  if((j%2)==1) return -1;
  else return 1;
}
Soku11 bardzo bardzo cię proszę jeszcze raz czy mógłbyś poprawić mój program - bo to co napisałem z tym obliczaniem wyznacznika to kompletna bzdura - sam już nie wiem jak to przekazać przez wskaźnik (**zmienna), spora część kodu na wyznacznik wzięłem stąd :

Kod: Zaznacz cały

http://matematyka.pl/50749.htm
(jak widać tamtego kodu wogóle niezrozumiałem)

A generalnie chciałem policzyć wyznacznik metodą LaPlace'a : w taki sposób żeby: w tym wzorze Laplace'a wywoływał obliczoną wartość minora z funkcji minor i coś mi wogóle nie wyszło korzystając z powyższego kodu. A nie mam już siły męczyć się z obliczeniem tego programu - tym bardziej że muszę się przygotować jeszcze do innych przedmiotów - także bardzo bardzo bym Cię prosił soku11 o napisanie gotowej poprawionej funkcji dla tego zadania z wykorzystaniem wskaźnika (oczywiście przydałoby się wyjaśnienie jeśli funkcja ta byłaby dość skomplikowana; a proszę cię nie używaj funkcji mallorc, callorc czy jak one się nazywają bo ich wogóle na wykładach jeszcze nie miałem).
Jeśli zrobiłbyś dla mnie tą przysługę to byłbym ci bardzo wdzięczny! :(
soku11
Użytkownik
Użytkownik
Posty: 6607
Rejestracja: 16 sty 2007, o 19:42
Płeć: Mężczyzna
Podziękował: 119 razy
Pomógł: 1823 razy

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: soku11 »

To, ze po angielsku to nawet lepiej. Sam nie lubie programowac z uzyciem polskiego jezyka :)

Napisalem juz ci wielokrotnie, ze samo przekazywazanie tej tablicy jest przez wskaznik! Uparles sie, zeby przekazywac tablice statyczna z uzyciem nieszczesnego symbola '*', to podalem ci kod i dwie metody na odwolywanie sie do tej tablicy (patrz wczesniejszy kod i funkcja void funArray2D(int* tab,int dim);). Jesli chcesz miec w funkcji odwolania za pomoca ** (wskaznik na wskaznik, czyli tablica wskaznikow), to musisz stworzyc tablice DYNAMICZNIE. Podskreslam MUSISZ, bo tylko tablice dynamiczne sa postaci tablicy wskaznikow. Tablice wielowymiarowe sa to poprostu ciagle tablice jednowymiarowe z odpowiednim obliczeniem offsetow. Takze nie odwolasz sie do nich za pomoca ** (chyba, ze cos zapomnialem). Oto gotowiec bez jakiejkolwiek kontroli bledow uzywajac twojego znaczka ** (z uzyciem malloc, bo inaczej sie nie da; tak chcesz, to tak masz):

Kod: Zaznacz cały

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define DIMENSION 3

int** create(int dim);
void fill(int** tab, int dim);
void show(int** tab, int dim);
int calculateDet(int** tab,int dim);
void destroy(int** tab,int dim);


int main()
{
  int** tab=NULL;
  tab=create(DIMENSION);

  fill(tab,DIMENSION);
  show(tab,DIMENSION);

  printf("Wyznacznik=%d\n",calculateDet(tab,DIMENSION));

  destroy(tab,DIMENSION);
  return 0;
}


int** create(int dim)
{
  int i=0;
  int** tmpTab=NULL;

  tmpTab=(int**) malloc(dim*sizeof(int*));  // tworzenie dynamiczne tablicy wskaznikow

  for(i=0;i<dim;++i)
    tmpTab[i]=(int*) malloc(dim*sizeof(int)); // stworzenie tablicy w tablicy (tablicy dla poszczegolnych komorek)

  return tmpTab;
}

void fill(int** tab, int dim)
{
  int i=0;
  int j=0;

  for(i=0;i<dim;++i)
    for(j=0;j<dim;++j)
    {
      printf("Podaj element tab[%d][%d]: ",i,j);
      scanf("%d",&tab[i][j]);
    }
}


void show(int** tab, int dim)
{
  int i=0;
  int j=0;

  for(i=0;i<dim;++i)
  {
    for(j=0;j<dim;++j)
      printf("tab[%d][%d]= %d\t",i,j,tab[i][j]);
    printf("\n");
  }
}

int calculateDet(int** tab,int dim)
{
  int i=0;
  int j=0;
  int j1=0;
  int j2=0;
  double det = 0;
  int **m=NULL;

  if(dim==1)
    det=tab[0][0];
  else if(dim==2)
  {
    det=tab[0][0]*tab[1][1]-tab[1][0]*tab[0][1];
  }
  else
  {
    det=0;
    for(j1=0;j1<dim;++j1)
    {
      m=create(dim-1);

      for(i=1;i<dim;++i)
      {
        j2=0;
        for(j=0;j<dim;++j)
        {
          if(j==j1)
            continue;
          m[i-1][j2]=tab[i][j];
          ++j2;
        }
      }

      det+=pow(-1.0,j1+2.0)*tab[0][j1]*calculateDet(m,dim-1);
      destroy(m,dim-1);
    }
  }

  return det;
}


void destroy(int** tab,int dim)
{
  int i=0;

  for(i=0;i<dim;++i)
    free(tab[i]);

  free(tab);
}

Jest to dzialajacy gotowiec bez wyciekow pamieci i bez kontroli bledow. Normalnie, za taki kod pobieram oplate, ale juz mi sie nie chce tobie tlumaczyc, bo wogole nie czytasz moich postow... Zeby nie bylo - kod SKOPIOWANY z linka na stronie podanej przez ciebie, nieco zmodyfikowany. Na tablicach statycznych (bez malloc) masz kod gotowy w twoim linku...

Pozdrawiam.
Nighthunter24
Użytkownik
Użytkownik
Posty: 27
Rejestracja: 7 mar 2009, o 10:41
Płeć: Mężczyzna

[C] Dwuwymiarowe tablice i wyznacznik

Post autor: Nighthunter24 »

Okazało się że w moim programie (mówię jeszcze o tym bez tego symbolu"*") przy sprawdzeniu czy wprowadzona przez użytkownika wartość jest liczbą całkowitą nie jest konieczne uwzględnienie przypadku wprowadzenia znaku (pytałem się prowadzącego, a zatem mogę użyć float). Napisałem ten warunek sprawdzający dla typu integer (w kodzie jest to : if((b-((int)(b/1)))>0) ), ale jest jeden haczyk : a mianowicie jak uwzględnić taki przypadek że użytkownik wpisał złą liczbę, czyli np: 2.5 - w tym momencie program informuje użytkownika o błędzie, (tu się zaczyna mój problem) i powinien tak długo go prosić o wpisanie tej wartości dopóki wpisze poprawny typ liczby - jak to zrobić bo myślałem co tu napisać i dalej nie wiem jak? (bardzo prosiłbym jeszcze raz o pomoc).

Kod: Zaznacz cały

void Fill(int tab[3][3]) /*prototype of function Fill*/
{
  int i, j;
  float b;
  
  for(i=0; i<3; i++)
  {
    for(j=0; j<3; j++)
    {
      do
      {
        printf("Write integer number <0,10> for a[%d][%d] = ", i, j);
        scanf("%f", &b); /*reading of elements of matrix which are
		written by user*/
        if((b-((int)(b/1)))>0)
        {
           printf("Wrong type of number
");
           printf("Please write integer number <0,10> for a[%d][%d] = ", i, j);
        }
      }
      while(b<0 || b>10); 
	  /*the condition of filling in elements of matrix with numbers <0,10>*/
    }
  }
  
  printf("
");
}
ODPOWIEDZ