[C++] szybkość tablicy dynamicznej

0

Problem wynika głównie z chęci przeniesienia się z Dev'a na Visuala - chodzi o tablice o nieznanym w czasie kompilacji rozmiarze. Jako że Visual, w przeciwieństwie do Dev'a, takich praktyk nie akceptuje, muszę przerobić ów tablicę na tablicę dynamiczną (z góry zdefiniowany rozmiar tablicy to raczej ostateczność), lub zastosować jakiś inny myk.

Tak wygląda części programu, której problem dotyczy:

...                                                  
int main() 
{ 
  ...                                                //wczytywanie danych, inicjalizacja zmiennych etc...
  float Map[x][y][2];                                //kłopotliwa tablica - rozmiar x i y wczytywane są z pliku
  ...                                                //dalsza część inicjalizacji
  ...
  {                                                  //wnętrze głównej pętli programu
    ...                                              //obsługa zdarzeń
    for(int n=0; n<precision; n++)                   //główna pętla licząca
    {
      for(int l=1; l<x-1; l++)
      {
        ...                                          //obsługa krawędzi tablicy
        for(int h=1; h<y-1; h++)                     //a oto główny winowajca procesorożerności programu
        { 
          Map[l][h][1]-=(Map[l][h][0]-(Map[l+1][h][0]+Map[l-1][h][0]+Map[l][h+1][0]+Map[l][h-1][0])*0.25)*factorA;
        }
      }
      for(int h=1; h<y-1; h++)
      {
        ...                                          //obsługa krawędzi tablicy
      }
      ...                                            //obsługa rogów tablicy
      for(int l=0; l<x; l++)
      {
        for(int h=0; h<y; h++)
        {
          Map[l][h][1]*=(1-factorB);                 //a oto poboczni winowajcy procesorożerności
          Map[l][h][0]+=(Map[l][h][1]*factorC);
        }
      }
    }
    ...                                              //wyświetlanie tablicy i inne pomniejsze czynności(Allegro inside)
  }
  

Tak zorganizowany program, przy rozmiarach tablicy 255/255 i precyzji ustawionej w celach testowych na 16 wyciągał ~31 fps'ów. Ale tablicę tę musiałem przerobić na wersję dynamiczną, jeśli chciałbym przejść na Visuala. W celu tym utworzyłem strukturę która zastępuje 3 wymiar tablicy, i z tej struktury utowrzyłem vector vectorów. wszystko wygląda teraz mniej więcej tak:

struct Cell                                                                        //komórka zastępująca 3 wymiar tablicy
{
  float x, dx;
  Cell::Cell(float nx = 0, float ndx = 0):
  x(nx), dx(ndx){}      
};
Cell zeroCell(0.5, 0);
...                                                  
int main() 
{ 
  ...                                                //wczytywanie danych, inicjalizacja zmiennych etc...
  vector<Cell> buf;
  for(int h=0; h<y; h++)
    buf.push_back(zeroCell);
    
  vector<vector<Cell> > Map;
  for(int w=0; w<x; w++)
    Map.push_back(buf);                              //utworzenie jeszcze bardziej kłopotliwej tablicy
  ...                                                //dalsza część inicjalizacji
  ...
  {                                                  //wnętrze głównej pętli programu
    ...                                              //obsługa zdarzeń
    for(int n=0; n<precision; n++)                   //główna pętla licząca
    {
      for(int l=1; l<x-1; l++)
      {
        ...                                          //obsługa krawędzi tablicy
        for(int h=1; h<y-1; h++)                     //a oto główny winowajca procesorożerności programu
        { 
          Map[l][h].dx-=(Map[l][h].x-(Map[l+1][h].x+Map[l-1][h].x+Map[l][h+1].x+Map[l][h-1].x)*0.25)*factorA;
        }
      }
      for(int h=1; h<y-1; h++)
      {
        ...                                          //obsługa krawędzi tablicy
      }
      ...                                            //obsługa rogów tablicy
      for(int l=0; l<x; l++)
      {
        for(int h=0; h<y; h++)
        {
          Map[l][h].dx*=(1-factorB);                 //a oto poboczni winowajcy procesorożerności
          Map[l][h].x+=(Map[l][h].dx*factorC);
        }
      }
    }
    ...                                              //wyświetlanie tablicy i inne pomniejsze czynności(Allegro inside)
  }

I ku mojemu ogromnemu zasmuceniu, program wyciągał... ledwie ponad 3 klatki na sekundę.

Czy jest jakiś sposób na przeniesienie się z tym kodem do visuala bez utraty prędkości? niby fajne środowisko, ale nie będę przez to tak kaleczył programu.
Może 'ręczne' utworzenie tablicy dynamicznej poprawi tą sytuację? spodziewam się że trochę roboty z tym będzie, a nie chcę marnować czasu, poza tym wątpię żeby twórcy vectora tak nawalili...
Poza tym, jak to jest z tymi tablicami o rozmiarach ustalonych przez zmienne - powinno tak się robić, można tak robić? jaki jest status takich praktyk? W visualu to error, w Dev'ie nawet ostrzeżenie nie wyskakuje...

Gdyby kogoś interesowało - program jest symulatorem fal.

0

Robisz tablicę jednowymiarową i jeździsz po niej jak chcesz.

struct Elem { float a,b; }; // możesz zrobić sobie operator[], lub makro

Elem map = new Elem[xy];

map[ix + j].a = ... ; // Map[i][j][0] = ...
map[i
x + j].b = ... ; // Map[i][j][1] = ...

W pętli szybciej będzie na wskaźniku, albo raz wymnożyć d = i*x + j, a potem tylko dodawać offsety...

0

Ale tablicę tę musiałem przerobić na wersję dynamiczną, jeśli chciałbym przejść na Visuala.

Co ty to pleciesz czlowieku ... :|

0

Tak się kończy nadmierne wykorzystywanie rozszerzeń kompilatora.

0

Był o tym temat chyba wczoraj. Devcpp nie krzyczy bo g++ bez żadnych flag kompiluje taki kod, ale jest to niezgodne ze standardem języka. Jak dasz mu flagi -ansi -pedantic -Wall to okaze się że i w Devie ci nie przejdzie. Jak widać programowanie niezgodne ze standardami powoduje same blędy i sprawia że kod jest nieprzenośny na inne kompilatory.
Spróbuj to twoje nieszczęsne
float Map[x][y][2];
zamienić na alokacje pamięci na pomocą new[]. Powinno być troche szybsze niż korzystanie z kontenerów (bo istotą kontenerów jest wygoda korzystania, a nie szybkość)

0

jeśli już faktycznie chcesz w tym wypadku korzystać z std::vector to przed includem zdefiniuj
#define _SCL_SECURE 0

0

Jezeli g++ pozwala na takie cos, to czy jest jakis sposob na zwolnienie pamieci zajmowanej przez taką tablicę? Jeżeli nie ma, to raczej bez sensu to jest, wyciek gotowy. I ciekawi mnie jak to jest traktowane - czy tak samo jak utworzenie tablicy dynamicznej za pomocą new?

0

Tak jak VLA w C - jeśli tablica jest zrobiona jako automatyczna, to jest automatyczna, proste.

0

Problem rozwiązany - tablica dynamiczna zaalokowana ręcznie tak jak standard przykazał + ustawienie 3 wymiaru jako pierwszy ([2]) i obsługa za pomocą osobnych wskaźników (jako 2 osobnymi tablicami) dało prawie dwukrotne przyśpieszenie względem oryginalnego rozwiązania, i błędu przy dużych rozmiarach nie wywala.

0
othello napisał(a)

Jezeli g++ pozwala na takie cos, to czy jest jakis sposob na zwolnienie pamieci zajmowanej przez taką tablicę? Jeżeli nie ma, to raczej bez sensu to jest, wyciek gotowy. I ciekawi mnie jak to jest traktowane - czy tak samo jak utworzenie tablicy dynamicznej za pomocą new?
Najpierw tablica jest umieszczana na stosie (coś jaka funkcja "alloca"), później wywoływany jest konstruktor na każdej komórce (coś jak "placement new") jeśli takowy istnieje. Przed wyjściem z funkcji wywoływany jest destruktor na każdej komórce jeśli istnieje a funkcja kończąc działanie ściąga wszystko co swoje ze stosu łącznie z tablicą.

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