Wieso schreiben C++ Progger for(int i=0; i!=99... anstatt i<99
-
hustbaer schrieb:
groovemaster schrieb:
kreater schrieb:
warum schreiben manche for(;;) statt while(true)?
Weil das diverse Compiler weniger zu Warnungen veranlasst.
Bzw. weil "for(;;)" einfach viel kuuhler ist

Weil das die C-Programmierer auch schon so gemacht haben.
Und die hatten schließlich coole Frisuren und flotte Hüte!
-
Ich hatte es auch irgendwo gelesen. Zum einen ist ein
for(;; )einfach kürzer, zum anderen passt es besser zuforever.
-
lagalopex schrieb:
Ich hatte es auch irgendwo gelesen. Zum einen ist ein
for(;; )einfach kürzer, zum anderen passt es besser zuforever.
Wie meinst du das? So?
#define forever for(;;)for(;; )finde ich jetzt aber hässlicher alswhile(true)- bei der While-Variante sieht man meiner Ansicht nach auch schneller, worum es sich handelt. Aber das ist natürlich Geschmackssache (einmal abgesehen davon, dass solche Endlosschleifen sowieso kaum geschrieben werden).
-
Oder gleich
#define ever (;;) for ever { }
-
hustbaer schrieb:
Oder gleich
#define ever (;;) for ever { }
:p
-
CppProgger schrieb:
Das hat doch nen Grund?
der grund ist fehlende weitsicht. viele c++ entwickler sind seltsamerweise der meinung, dass code nicht kindersicher sein muss, da man ihn ja selbst geschrieben hat und auch ein blinder mit krückstock sofort durchblickt.
for( int i = 0; i != 99; ++i ) { // paar zeilen code }ist unglaublich fehleranfällig. ein unbedarfter zweiter (oder derselbe entwickler, kommt vor) könnte auf die idee kommen, den code irgendwie zu "verbessern" und folgendes einbauen
for( int i = 0; i != 99; ++i ) { // paar zeilen code if( somethingImportant ) i += 3; }und schon hat man die wunderschönsten fehler im programm.
-
Vielleicht wird != um eine Tausendstel Sekunde schneller ausgewertet als <. Wäre gar nicht so unlogisch. Bei != kann die Funktion beim erstbesten Bit zurückkehren, das nicht übereinstimmt. Bei < ist die Sache nicht so eindeutig, bzw. müssen im Durchschnitt immer ein paar Bits mehr miteinander verglichen werden -> ergo -> dauert deshalb eventuell minimal länger. Ist aber nur eine Theorie. Man würde gar nicht vermuten, in wie vielen Fällen ein Stück Code sich in Punkto Laufzeit von einem anderen Stück Code unterscheidet, das eigentlich genau das gleiche tut, aber eben mithilfe anderer Operatoren.
Kleines Beispiel:
int a = f(); if(a < 3) a += 3; else a += 6;Scheinbar gleichwertig ist z.B.:
int a = f(); a += a < 3 ? 3 : 6;Der Laufzeitunterschied ist zwar minimal, aber die zweite Version ist z.B. bei 200 Mio. Schleifendurchläufen auf meinem Rechner um ca. 1/100 Sekunde schneller (extra getestet).
Es ist gut vorstellbar, dass solche mikroskopischen Laufzeitunterschiede auch zwischen dem < und dem != Operator bestehen (falls der Compiler solche Fälle automatisch erkennen sollte und dementsprechend ohne Zutun des Proggers bei der Übersetzung optimiert ist es wohl einerlei, ob man < oder != schreibt.)
-
Theorien-Erfinder schrieb:
Bei != kann die Funktion beim erstbesten Bit zurückkehren
Was für Funktionen denn? Das ganze wird in Maschinencode übersetzt und da macht es zeitlich keinen Unterschied, ob du auf Gleichheit oder Kleinerheit (wie heisst das auf Deutsch?) überprüfst.
-
Nanyuki schrieb:
Theorien-Erfinder schrieb:
Bei != kann die Funktion beim erstbesten Bit zurückkehren
Was für Funktionen denn? Das ganze wird in Maschinencode übersetzt und da macht es zeitlich keinen Unterschied, ob du auf Gleichheit oder Kleinerheit (wie heisst das auf Deutsch?) überprüfst.
So, und ab sofort ist es keine Theorie mehr, sondern eine Tatsache:
!= ist geringfügig schneller als <Dieses Programm diente zur Überprüfung:
#include <windows.h> #include <stdio.h> int main(){ long dummy = 0; LARGE_INTEGER a,b; /* Erste Version */ QueryPerformanceCounter(&a); for(int i = 0; i != 200000000; ++i) dummy += i & 1 ? 1 : 0; QueryPerformanceCounter(&b); printf("Dauer !=: %I64d QueryTakte\n" "Es gibt %d ungerade Zahlen\n", b.QuadPart-a.QuadPart, dummy); /* Zweite Version */ dummy = 0; QueryPerformanceCounter(&a); for(int i = 0; i < 200000000; ++i) /* Einziger Unterschied: < statt != */ dummy += i & 1 ? 1 : 0; QueryPerformanceCounter(&b); printf("Dauer <: %I64d QueryTakte\n" "Es gibt %d ungerade Zahlen\n", b.QuadPart-a.QuadPart, dummy); fgetc(stdin); return 0; }Und das war der Output:
Dauer !=: 2358403 QueryTakte Es gibt 100000000 ungerade Zahlen Dauer <: 2465883 QueryTakte Es gibt 100000000 ungerade ZahlenEs wurde zuerst die Laufzeit der != Schleife gestoppt,
und danach die Laufzeit einer ansonsten äquivalenten < Schleife.
Der Unterschied beträgt ca. 100.000 Query-Takte, (das entspricht auf meinem Rechner ungefähr eine Vierzigstel-Sekunde).--> Falls 2.465.883 größer als 2.358.403 sein sollte, so ist auch der != Operator schneller als der < Operator. Genau wie ich vermutet hatte. Solche Schreibweisen-Tricks haben meistens mit Laufzeit-Optimierung zu tun.
-
So ein Schwachsinn, eine 1/40 Sekunde - das ist doch mit geraumer Wahrscheinlichkeit nur ein Messfehler.
Wiederhole die Messung erstmal auf paar hundert verschiedenen Rechnern mit mehreren tausend Testläufen, bevor du hier irgendwelche wilden Behauptungen in den Raum stellst!Das hier ist im Übrigen meine Ausgabe:
Dauer !=: 957994 QueryTakte Es gibt 100000000 ungerade Zahlen Dauer <: 946040 QueryTakte Es gibt 100000000 ungerade Zahlen--> Falls 957.994 größer als 946.040 sein sollte, so ist deine Theorie ziemlicher Mist. Genau wie ich vermutet hatte. Solche Schreibweisen-Tricks bringen in der Praxis absolut rein gar nichts.
-
Aber Interessant, bei mir liegt die <-Version fast immer hinten. Vielleicht ist da doch ganz ganz ganz wenig Wahres dran.
Die obige Messung ist übrigens noch gut, meistens liegt die <-Version 15k-25k Takte dahinter.
-
Theorien-Erfinder schrieb:
Vielleicht wird != um eine Tausendstel Sekunde schneller ausgewertet als <. Wäre gar nicht so unlogisch. Bei != kann die Funktion beim erstbesten Bit zurückkehren, das nicht übereinstimmt. Bei < ist die Sache nicht so eindeutig, bzw. müssen im Durchschnitt immer ein paar Bits mehr miteinander verglichen werden -> ergo -> dauert deshalb eventuell minimal länger. Ist aber nur eine Theorie.
Nette Theorie, sie ignoriert leider die Funktionsweise von Rechnern

Newsflash: Auch von Compilern. gcc scheint zumindest solche Standardmuster zu erkennen und generiert gleich nur eine jne-Instruktion (jump if not equal).
-
Gegner der Wissenschaft schrieb:
Aber Interessant, bei mir liegt die <-Version fast immer hinten. Vielleicht ist da doch ganz ganz ganz wenig Wahres dran.
Die obige Messung ist übrigens noch gut, meistens liegt die <-Version 15k-25k Takte dahinter.Klar müsste man das auf mehreren Rechnern überprüfen. Es könnte auch sein, dass ein und der gleiche Maschinenbefehl auf unterschiedlichen Rechnern jeweils geringfügig anders implementiert ist. Ich wollte nur darauf hinaus, dass unterschiedliche Maschinenbefehle idR unterschiedliche Laufzeiten haben, was meinem zitierten Vorredner vermutlich nicht bewusst war. Das Beispiel ist natürlich völlig unsinnig, aber um diese winzigen Laufzeitunterschiede aufzudecken, muss die Schleife möglichst oft durchlaufen werden.
Es gibt aber durchaus auch sinnvolle Anwendungen, in denen milliardenfach irgendwelche Schleifen durchlaufen werden sollen, dann könnte es interessant werden, sich mit diesen geringfügigen Laufzeitunterschieden zu beschäftigen.
Ich habe absichtlich ein zweites Beispiel im Code untergebracht, das noch deutlicher die unterschiedlichen Laufzeiten von Maschinenbefehlen zeigen könnte.Man ersetze
i & 1
jeweils durch
i % 2Oberflächlich betrachtet geschieht das gleiche: Man möchte herausfinden, ob eine Zahl ungerade ist. Es wird auch jeweils nur ein einziger Maschinenbefehl verwendet (BITAND bzw. MODULO). Trotzdem ist die Laufzeit der i % 2 - Variante erheblich länger.
Es gibt noch hunderte solcher Fälle.mfg
-
Bashar schrieb:
Theorien-Erfinder schrieb:
Vielleicht wird != um eine Tausendstel Sekunde schneller ausgewertet als <. Wäre gar nicht so unlogisch. Bei != kann die Funktion beim erstbesten Bit zurückkehren, das nicht übereinstimmt. Bei < ist die Sache nicht so eindeutig, bzw. müssen im Durchschnitt immer ein paar Bits mehr miteinander verglichen werden -> ergo -> dauert deshalb eventuell minimal länger. Ist aber nur eine Theorie.
Nette Theorie, sie ignoriert leider die Funktionsweise von Rechnern

Newsflash: Auch von Compilern. gcc scheint zumindest solche Standardmuster zu erkennen und generiert gleich nur eine jne-Instruktion (jump if not equal).
Auch Bashar glaubt, dass sich Maschinenbefehle nicht in der Laufzeit unterscheiden.
Und ich hab' keine Ahnung von der Funktionsweise eines Rechners. Ein Compiler, der optimiert, ohne dass man es ihm anschafft, ist der größte Feind eines Programmierers.
mfg
-
ihr seid ja alle lol, ich meinte "warum schreiben manche for(;;) statt while(true)" nicht wirklich als frage, denn wie ich weiter geschrieben hab "ist doch scheiss egal...

-
TheorienErfinder schrieb:
Auch Bashar glaubt, dass sich Maschinenbefehle nicht in der Laufzeit unterscheiden.

Wo liest du das raus?
-
Oh man, geringfügig schneller oder langsamer...
Wenn ihr das wissen wollt, guckt Euch den Assembler der betreffenden Stelle an, und sucht Euch die Cycles raus, die die Befehle haben. Alles andere ist Hokuspokus.
-
kreater schrieb:
warum schreiben manche for(;;) statt while(true)?
is doch scheiss egal...
Nicht wirklich, denn "while(true)" liefert überflüssige Compilerwarnungen, die man nicht wirklich braucht. "while(true)" ist somit die objektiv schlechtere Variante.
-
TheorienErfinder schrieb:
Man ersetze
i & 1
jeweils durch
i % 2Oberflächlich betrachtet geschieht das gleiche: Man möchte herausfinden, ob eine Zahl ungerade ist. Es wird auch jeweils nur ein einziger Maschinenbefehl verwendet (BITAND bzw. MODULO). Trotzdem ist die Laufzeit der i % 2 - Variante erheblich länger.
Es gibt noch hunderte solcher Fälle.mfg
das erkennt sogar der Mensch, dass das eine ne Division ist und das andere ein wesentlich schnelleres And.
MS VC++ 2008 EE z.B. optimiert das bereits in der Debug-Version (da es sich um einen konstanten Parameter handelt).
Das ist genauso wie (i * 4) und (i << 2).laut intel ist je/jne (!=) genauso schnell wie jg/jl (<) oder ja/jb (<),
tiefer kann man nicht gehn.--> + iteratoren.
--> + blaaaaa.
-
Theorien-Erfinder schrieb:
So, und ab sofort ist es keine Theorie mehr, sondern eine Tatsache:
!= ist geringfügig schneller als <Nope. Von der Theorie her hast du schon recht, ein Vergleich auf Gleichheit bzw Ungleichheit lässt sich effizienter implementieren. Die Praxis sieht nur ein klein wenig anders aus. x86 Legacy Code kennt nur eine allgemeine Vergleichsinstruktion, cmp. Dabei wird alles mögliche in Betracht gezogen, kleiner, gleich oder grösser, und die entsprechenden Flags gesetzt. Mittels Sprungbefehlen (jxx) können diese dann weiterverarbeitet werden.
So, und hier noch meine Ergebnisse (GCC4.3):
Dauer !=: 615678 QueryTakte Es gibt 100000000 ungerade Zahlen Dauer <: 927758 QueryTakte Es gibt 100000000 ungerade ZahlenWie du sehen kannst, unterscheiden sich die Laufzeiten enorm. Interessant wird es aber erst, wenn man sich mal das Assembler Listing der Schleifen anschaut anschaut:
L2: mov eax, edx and eax, 1 add ebx, eax inc edx cmp edx, 200000000 jne L2 [...] L3: mov eax, edx and eax, 1 add ebx, eax inc edx cmp edx, 200000000 jne L3Wie du sehen kannst, der Maschinencode ist identisch. Was also verursacht die unterschiedliche Laufzeiten? Es sind nicht die Operationen != oder <. Die Ursachen sind bei Arbeitsweise der CPU selbst zu suchen, wie Code Alignment, Prefetching, Caching, usw.