1. Dashboard
  2. Forum
    1. Unerledigte Themen
  3. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team-Mitglieder
    4. Trophäen
    5. Mitgliedersuche
  4. Tutorial Bereich
  • Anmelden
  • Registrieren
  • Suche
Dieses Thema
  • Alles
  • Dieses Thema
  • Dieses Forum
  • Seiten
  • Forum
  • Lexikon
  • Erweiterte Suche
  1. Informatik Forum
  2. Webmaster & Internet
  3. Entwicklung

Pointerarithmetik vs. Direktzugriff

  • \LaTeX
  • 9. September 2005 um 13:44
  • Unerledigt
  • \LaTeX
    7
    \LaTeX
    Mitglied
    Punkte
    425
    Beiträge
    66
    • 9. September 2005 um 13:44
    • #1

    Hallo Leute..

    Mich interessiert, welche Methode effizienter (im Sinne der Geschwindigkeit) ist. Die Methode mit dem Direktzugriff:

    Code
    #define INDEX(x,y,z) (z*xdim*ydim + y*xdim + x)
    unsigned int my_array = new unsigned int[xdim*ydim*zdim];
    ...
    unsigned int cur_a=0;
    
    
    for (int z=0; z<zdim; z++)
    {
      for (int y=0; y<ydim; y++)
      {
        for (int x=0; x<xdim; x++)
        {
          cur_a = my_array[INDEX(x,y,z)];
          ...
          // Zugriff auf die 26 Nachbarn des Elementes an der Position x,y,z
          if (my_array[INDEX(x-1,y-1,z-1)] < cur_a) // Nachbar: 01
          {
            ...
          }
          ...
          if (my_array[INDEX(x+1,y+1,z+1)] < cur_a) // Nachbar: 26
          {
            ...
          }
          ...
        }
      }
    }
    Alles anzeigen

    ... oder die mit Pointerarithmetik:

    Code
    ...
    unsigned int my_array = new unsigned int[xdim*ydim*zdim];
    unsigned int *cur_a=0;
    
    
    // nur 9 Verweise auf die Nachbarn (die restlichen Nachbarn
    // werden mittels Pointerarithmetik ermittelt)
    unsinged int *a01=0;
    unsinged int *a02=0;
    unsinged int *a03=0;
    ...
    unsinged int *a09=0;
    
    
    for (int z=0; z<zdim; z++)
    {
      for (int y=0; y<ydim; y++)
      {
        cur_a = &my_array[INDEX(x,y,z)];
        ...
        // Zugriff auf die 9 Nachbarn des Elementes an der Position x,y,z
        a01 = &my_array[INDEX(x-1,y-1,z-1)];
        ...
        a09 = &my_array[INDEX(x+1,y+1,z+1)];
    
    
        for (int x=0; x<xdim; x++)
        {
          ...
          if (*(a01+x) < cur_a) // Nachbar: 01
          {
            ...
          }
          if (*(a01+x+1) < cur_a) // Nachbar: 02
          {
            ...
          }
          if (*(a01+x+2) < cur_a) // Nachbar: 03
          {
            ...
          }
          ...
          if (*(a02+x) < cur_a) // Nachbar: 04
          {
            ...
          }
          if (*(a02+x+1) < cur_a) // Nachbar: 05
          {
            ...
          }
          if (*(a02+x+2) < cur_a) // Nachbar: 06
          {
            ...
          }
          ...
          ...
          if (*(a09+x) < cur_a) // Nachbar: 24
          {
            ...
          }
          if (*(a09+x+1) < cur_a) // Nachbar: 25
          {
            ...
          }
          if (*(a09+x+2) < cur_a) // Nachbar: 26
          {
            ...
          }
        }
      }
    }
    Alles anzeigen

    D.h. die konkrete Frage, die ich mir hier stelle ist, ob "if (*(a+x+1) < cur_a)" teurer ist als "if (my_array[z*xdim*ydim + y*xdim + x] < cur_a)"? Also auf der einen Seite [Zwei Additionen und ein Derefenzieren] und auf der anderen Seite [3 Multiplikationen und zwei Additionen]. Oder anders ausgedrueckt: dauert das Dereferenzieren eines Pointers laenger als wenn man 3 uint Werte multipliziert (wenn man die Ermittlung des Pointers a mal auszer Acht laeszt)?

    Koennt ihr mir eine Empfehlung geben, ohne, dass ich's jetzt selber testen muss?

    Danke im Voraus,
    ciao..

  • Shine
    7
    Shine
    Mitglied
    Punkte
    465
    Beiträge
    89
    • 9. September 2005 um 14:59
    • #2

    also ich bin jetzt ja dabei kein profi, aber ich würde fast sagen, dass man das allgemein gar net so sagen sagen..
    Soweit ich weiß, sind normalerweise additionen billiger als multiplikationen, allerdings kann ich mir durchaus vorstellen, dass das ganze auch auf deinen compiler ankommt, was er in welcher weise optimiert.

    außerdem würd ich bei beiden vorgehensweisen mal aufpassen, auf was du da zugreifst, weil die "Ränder des würfels" haben ja keine 26 nachbarn ;-), owa das nur nebenbei

    also ich würd ja die erste version bevorzugen, weil sie einfach viel leserlicher ist..
    aber vielleicht noch etwas.
    du führst rechnungen durch, die in der form zu oft durchgeführt werden, nämlich wird in jedem durchlauf der innersten schleife alles an multiplikationen durchgeführt, was net notwendig is...

    Code
    for (int z=0; z<zdim; z++)
    {
     
    // aeusserste multiplikation z * xdim * ydim
    int zMult = z* xdim* ydim;
    
    
      for (int y=0; y<ydim; y++)
      {
    // naechste multiplikation plus wert von vorher
    // yMult = zMult + y*xdim;
    int yMult = ZMult + y*xdim;
    
    
    	for (int x=0; x<xdim; x++)
    	{
    // und hier nur noch x dazu addieren
    	  cur_a = my_array[yMult+x];
    	  ...
    	  // Zugriff auf die 26 Nachbarn des Elementes an der Position x,y,z
    	  if (my_array[INDEX(x-1,y-1,z-1)] < cur_a) // Nachbar: 01
    	  {
    		...
    	  }
    	  ...
    	  if (my_array[INDEX(x+1,y+1,z+1)] < cur_a) // Nachbar: 26
    	  {
    		...
    	  }
    	  ...
    	}
      }
    }
    Alles anzeigen



    naja vielleicht bringt das ja was :winking_face:

    mfg Shine

  • jeuneS2
    11
    jeuneS2
    Mitglied
    Reaktionen
    17
    Punkte
    1.227
    Beiträge
    238
    • 9. September 2005 um 18:22
    • #3
    Zitat von \LaTeX

    D.h. die konkrete Frage, die ich mir hier stelle ist, ob "if (*(a+x+1) < cur_a)" teurer ist als "if (my_array[z*xdim*ydim + y*xdim + x] < cur_a)"? Also auf der einen Seite [Zwei Additionen und ein Derefenzieren] und auf der anderen Seite [3 Multiplikationen und zwei Additionen]. Oder anders ausgedrueckt: dauert das Dereferenzieren eines Pointers laenger als wenn man 3 uint Werte multipliziert (wenn man die Ermittlung des Pointers a mal auszer Acht laeszt)?


    Gute Compiler sollten x als Induktionsvariable erkennen und z*xdim*ydim+y*xdim als innerhalb der innersten Schleife konstanten Ausdruck und dementsprechend zweitere Form in erstere Überführen (irgendwo in den Unterlagen zur LVA Optimierende übersetzer findet sich ein schönes Beispiel dafür). Im Zweifelsfall würde ich aber Benchmarks vornehmen, nicht jeder Compiler macht auch immer das, was möglich wäre.

    PS: "dereferenzieren" ist quasi kostenlos, in der internen Darstellung der meisten Compiler ist a[i] das gleiche wie *(a+i) - sofern die Elemente des Arrays die Größe 1 haben, versteht sich.

    Why bother spending time reading up on things? Everybody's an authority, in a free land.

  • Plantschkuh!
    24
    Plantschkuh!
    Mitglied
    Reaktionen
    163
    Punkte
    6.173
    Beiträge
    1.181
    • 10. September 2005 um 16:49
    • #4
    Zitat von \LaTeX

    Also auf der einen Seite [Zwei Additionen und ein Derefenzieren] und auf der anderen Seite [3 Multiplikationen und zwei Additionen].


    Naja, zwei Additionen und nix ist unoptimiert sicher billiger als zwei Additionen und irgendwas... Und den Speicherzugriff hast du bei beiden Varianten dabei.

    Zitat von jeuneS2

    in der internen Darstellung der meisten Compiler ist a[i] das gleiche wie *(a+i) - sofern die Elemente des Arrays die Größe 1 haben, versteht sich.


    Mehr noch: Laut C-Standard sind a[i] und *(a+i) völlig äquivalent. Das geht sogar so weit, daß man statt array[index] genauso auch index[array] schreiben darf, da die Addition ja kommutativ ist...
    Und die Größe der Array-Elemente ist unerheblich, da Zeiger-Offsets immer automatisch in Elementen, nicht in Bytes ö.ä. gezählt werden.

    *plantsch*

  • hal
    32
    hal
    Mitglied
    Reaktionen
    52
    Punkte
    11.122
    Beiträge
    2.208
    • 11. September 2005 um 05:52
    • #5
    Zitat von Plantschkuh!

    Mehr noch: Laut C-Standard sind a[i] und *(a+i) völlig äquivalent. Das geht sogar so weit, daß man statt array[index] genauso auch index[array] schreiben darf, da die Addition ja kommutativ ist...

    hmmm...

    Code
    main() {
            char str[] = "hallo!";
            printf("%c\n",str[3]);
            printf("%c\n",3[str]);
    }

    funktioniert tatsächlich! Selbst nach 7 Jahren C-Erfahrung kann man trotzdem noch was dazulernen... Danke Plantschkuh! :grinning_squinting_face:

    Dieses Wissen hilft mir aber wohl eher für den C-Obfuscation-Wettbewerb als anderswo... Die komplizierteste Art, 1+1 zu rechnen: &1[(char*)1] :grinning_squinting_face:

    [font=verdana,sans-serif]"An über-programmer is likely to be someone who stares quietly into space and then says 'Hmm. I think I've seen something like this before.'" -- John D. Cock[/font]

    opentu.net - freier, unzensierter Informationsaustausch via IRC-Channel!
    Hilfe und Support in Studienangelegenheiten, gemütliches Beisammensein, von und mit Leuten aus dem Informatik-Forum!

  • \LaTeX
    7
    \LaTeX
    Mitglied
    Punkte
    425
    Beiträge
    66
    • 12. September 2005 um 14:26
    • #6
    Zitat von Shine


    außerdem würd ich bei beiden vorgehensweisen mal aufpassen, auf was du da zugreifst, weil die "Ränder des würfels" haben ja keine 26 nachbarn ;-), owa das nur nebenbei

    Klar, das war auch durch '...' im Code repraesentiert :) Die Raender musst ja eh' fuer beide Varianten ueberpruefen.

    Zitat von Shine

    du führst rechnungen durch, die in der form zu oft durchgeführt werden, nämlich wird in jedem durchlauf der innersten schleife alles an multiplikationen durchgeführt, was net notwendig is...

    naja vielleicht bringt das ja was :winking_face:

    Da hast' Recht, danke fuer'n Hinweis.

    Zitat von Plantschkuh!

    Naja, zwei Additionen und nix ist unoptimiert sicher billiger als zwei Additionen und irgendwas... Und den Speicherzugriff hast du bei beiden Varianten dabei.

    Cool, d.h. der Dereference Operator ist zur Laufzeit in diesem Fall "for free"?

    Danke nochmals fuer euere Beitraege. Jetzt ist einiges klarer.
    ciao

  • Plantschkuh!
    24
    Plantschkuh!
    Mitglied
    Reaktionen
    163
    Punkte
    6.173
    Beiträge
    1.181
    • 18. September 2005 um 15:19
    • #7
    Zitat von \LaTeX

    Cool, d.h. der Dereference Operator ist zur Laufzeit in diesem Fall "for free"?


    Nein, Speicherzugriffe sind nicht for free, sie sind sogar vergleichsweise teuer. Ich wollte nur ausdrücken, daß * und [] beides Operatoren zur Dereferenzierung sind, also hast du bei beiden die gleichen Kosten für den Speicherzugriff.

    *plantsch*

  • Maximilian Rupp 27. Dezember 2024 um 12:06

    Hat das Thema aus dem Forum Programmieren nach Entwicklung verschoben.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!

Benutzerkonto erstellen Anmelden

Benutzer online in diesem Thema

  • 1 Besucher

Rechtliches

Impressum

Datenschutzerklärung