Stilfrage zu meinem Code



    • schrieb:

    ich versuche die for-Schleife nicht zu missbrauchen, und habe fast nirgends eine stehen (weil ich keine Zählschleifen habe)

    Ist beides veraltet. Heutzutage schreibt man

    for (int i : range(0, 10))
      // mach was mit i
    

    und

    for (double d : istream_range<double>(std::cin))
      // mach was mit d
    

    Die Helferklassen zu schreiben ist trivial.



  • c++11kiddy schrieb:

    • schrieb:

    ich versuche die for-Schleife nicht zu missbrauchen, und habe fast nirgends eine stehen (weil ich keine Zählschleifen habe)

    Ist beides veraltet. Heutzutage schreibt man

    for (int i : range(0, 10))
      // mach was mit i
    

    Hab damit keine supi Erfahrungen gemacht, weil sie ruck zuck eklig werden, wenn die Schleifen nicht ganz so einfach sind.


  • Mod

    Beides völliger Unsinn.
    (Und mit Unsinn beziehe ich mich auf die Lesbarkeit, die sich dadurch kein Stück verbessert hat)

    Edit: Ich mache erstmal noch keine Aussagen bezüglich Performance...



  • volkard schrieb:

    Hab damit keine supi Erfahrungen gemacht, weil sie ruck zuck eklig werden, wenn die Schleifen nicht ganz so einfach sind.

    Man muss daran auch nicht pragmatisch festhalten.

    Einfache Schleifen einfaches for.
    Komplizierte Schleifen komplexes for.

    • schrieb:

    Edit: Ich mache erstmal noch keine Aussagen

    👍


  • Mod

    Jetzt darf ich Aussagen tätigen.
    Edit: Folgende Implementierung ist natürlich vereinfacht.

    #include <iostream>
    
    template< typename Type >
    struct range_impl
    {
    	Type a, b;
    
    	range_impl( Type a, Type b ):
    		a{a}, b{b} {}
    
    	struct Proxy
    	{
    		Type val;
    
    		Proxy( Type m ):
    			val(m) {}
    
    		bool operator!=( Proxy const& p ){ return val != p.val; }
    		Proxy& operator++(){ ++val; return *this; }
    		Type operator*() { return val; } // prvalue
    	};
    
    	Proxy begin() { return a; }
    	Proxy end() { return b; }
    };
    
    template< typename Type >
    range_impl<Type> range( Type a, Type b ) { return {a, b}; }
    
    int main()
    {
    	unsigned value = 0;
    	auto first = clock();
    
    	for( auto i : range_impl<unsigned>(0, 1 << 31 ) )
    		value += i;
    
    	std::cout << "Time: " << clock() - first << " value: " << value << '\n';
    
    	value = 0; first = clock();
    
    	for( unsigned i = 0; i != 1 << 31; ++i )
    		value += i;
    
    	std::cout << "Time: " << clock() - first << " value: " << value << '\n';
    }
    

    Ergibt, dass deine Variante ohne Optimierungslevel etwa 1.1 bis 1.2 mal mehr Zeit braucht. (Getestet auf Clang 3.3 und GCC 4.9)

    Edit: Deine Variante ist natürlich nur etwas langsamer ohne Optimierung. Mit Optimierung wird wahrscheinlich die zweite Schleife wegoptimiert... daher macht das Beispiel wenig sinn...



  • @ *
    Danke. Ich wusste gar nicht, dass man eine for Schleife so benutzen kann.
    In deinem Beispiel wurde das Problem der Initialisierung der beiden Variablen min und max gelöst, worüber ich die ganze Zeit schon nachgedacht habe.
    Und das ist genau das, was ich in meinem Anfangspost gemeint hatte. Wenn ich dann soetwas lese, ist es plötzlich logisch für mich.
    "Wenn ich nicht möchte, dass die Variablen immer wieder initialisiert werden, muss die Initialisierung außerhalb der Schleife statt finden."

    Zu deiner Frage, warum mein Code mehr macht, als in der Aufgabe stand:
    Die Aufgabe hat aufeinander aufgebaut. Die Aufgabe, um die sich der Thread handelt ist Nr. 6.
    Hier mal die genauen Aufgabenstellungen:

    1. Schreiben Sie ein Programm, das aus einer while-Schleife besteht, die bei jedem Schleifendurchlauf zwei int-Werte einliest und diese dann ausgibt. Verlassen Sie das Programm, wenn zum Beenden ein '|' eingegeben wurde.

    2. Ändern Sie das Programm so, dass die Ausgabe lautet: „Der kleinere Wert ist: “, gefolgt von der kleineren der beiden Zahlen und weiter „Der größere Wert ist:“, gefolgt von dem größeren Wert.

    3. Erweitern Sie das Programm so, dass es die Zeile „Die Zahlen sind gleich“ ausgibt, wenn die Zahlen gleich sind.

    4. Ändern Sie das Programm so, dass es double-Werte statt int-Werte verwendet.

    5. Ändern Sie das Programm so, dass es erst die größere und dann die kleinere Zahl ausgibt und anschließend die Zeile „Die Zahlen sind fast gleich“, wenn die beiden Zahlen sich um weniger als 1,0/10.000.000 unterscheiden.

    6. Ändern Sie jetzt den Schleifenrumpf, sodass er bei jedem Schleifendurchlauf nur einen double Wert einliest. Definieren Sie zwei Variablen um festzuhalten, welcher Wert bisher der kleinste und bisher der größte war. Geben Sie nach jedem Schleifendurchlauf den eingegebenen Wert aus. Wenn es der bisher kleinste Wert war, schreiben Sie nach der ausgegebenen Zahl „bisher der kleinste Wert“, und wenn es der bisher größte Wert war, schreiben Sie nach der Zahl „bisher der größte Wert“.

    @Hustbaer

    Ich glaube, dass du einen etwas falschen Eindruck vom Remixen und dem Musik machen ansich hast.
    Vielleicht habe ich deinen Post ja auch nur falsch verstanden, jedoch klingt deine Aussage nach:
    "Kein Musikproduzent weiß was er da macht, denn ansonsten könnte es keine neue Musik mehr geben."

    Als Musiker muss man genau so wissen, was man mit den 12 Noten macht, die einem zur Verfügung stehen. Jeder der sich mal etwas mit Musiktheorie beschäftigt hat, weiß was ich meine.
    Ganz Kritisch wird es im Mixing und Mastering. Wenn man da etwas falsch macht, klingt es ganz schnell, ganz schön scheiße.
    Es soll jetzt hier aber nicht weiter um Musik gehen. Nur als Ergänzung... 😉



    • schrieb:

    Jetzt darf ich Aussagen tätigen.
    [...]
    Ergibt, dass deine Variante selbst mit -O2 immer noch etwa 1.1 bis 1.2 mal mehr Zeit braucht. (Getestet auf Clang 3.3 und GCC 4.9)

    Nächstes Mal bitte richtig messen, danke.

    Ich bin überzeugt, dass, wenn du zuerst die normale for-Loop testest und dann die range-based, dass dann die range-based schneller ist.

    Wieso? Weil erst std::cout << "Time: " aufgerufen wird, was dazu führt das die Bibliothek geladen werden muss und dann erst clock(). Das zweite Mal ist sie schon da.

    Aber es ist sinnlos zu messen, denn beide erzeugen den gleichen Assemblercode, deshalb sind beide gleich schnell.

    Darum bleibe bei:

    • schrieb:

    Edit: Ich mache erstmal noch keine Aussagen


  • Mod

    Edit: Blödsinn.

    Aber es ist sinnlos zu messen, denn beide erzeugen den gleichen Assemblercode, deshalb sind beide gleich schnell.

    Verlinke mal GCC Explorer.



    • schrieb:

    ohne Optimierung:

    Wayne?

    Und warum kannst du nicht gcc-Explorer verlinken?

    http://gcc.godbolt.org/#{%22version%22%3A3%2C%22filterAsm%22%3A{%22labels%22%3Atrue%2C%22directives%22%3Atrue%2C%22commentOnly%22%3Atrue}%2C%22compilers%22%3A[{%22source%22%3A%22namespace%20{\ntemplate%20%3Ctypename%20Type%3E%20struct%20range_impl%20{\n%20%20Type%20a%2C%20b%3B\n\n%20%20range_impl%28Type%20a%2C%20Type%20b%29%20%3A%20a{%20a%20}%2C%20b{%20b%20}%20{}\n\n%20%20struct%20Proxy%20{\n%20%20%20%20Type%20val%3B\n\n%20%20%20%20Proxy%28Type%20m%29%20%3A%20val%28m%29%20{}\n\n%20%20%20%20bool%20operator!%3D%28Proxy%20const%20%26p%29%20{%20return%20val%20!%3D%20p.val%3B%20}\n%20%20%20%20Proxy%20%26operator%2B%2B%28%29%20{\n%20%20%20%20%20%20%2B%2Bval%3B\n%20%20%20%20%20%20return%20*this%3B\n%20%20%20%20}\n%20%20%20%20Type%20operator*%28%29%20{%20return%20val%3B%20}%20%2F%2F%20prvalue\n%20%20}%3B\n\n%20%20Proxy%20begin%28%29%20{%20return%20a%3B%20}\n%20%20Proxy%20end%28%29%20{%20return%20b%3B%20}\n}%3B\n\ntemplate%20%3Ctypename%20Type%3E%20range_impl%3CType%3E%20range%28Type%20a%2C%20Type%20b%29%20{\n%20%20return%20{%20a%2C%20b%20}%3B\n}\n}\n\nvoid%20f%28int%29%3B\n\nvoid%20a%28%29%20{\n%20%20for%20%28auto%20i%20%3A%20range_impl%3Cunsigned%3E%280%2C%201%20%3C%3C%2031%29%29\n%20%20%20%20f%28i%29%3B\n}\nvoid%20b%28%29%20{\n%20%20for%20%28unsigned%20i%20%3D%200%3B%20i%20!%3D%201u%20%3C%3C%2031%3B%20%2B%2Bi%29\n%20%20%20%20f%28i%29%3B\n}%22%2C%22compiler%22%3A%22%2Fopt%2Fclang-3.3%2Fbin%2Fclang%2B%2B%22%2C%22options%22%3A%22-O3%20-std%3Dc%2B%2B11%22}]}


  • Mod

    Wayne?

    Ich werde doch keine Optimierung anschalten. Dann bist du doch bei diesem Beispiel im Nachteil.

    Edit: NAtürlich, bei deinem GCC-Explorer-Beispiel ist Optimierung angebracht.

    Hier:

    int main()
    {
    	unsigned value = 0;
    	auto first = clock();
    
    	for( unsigned i = 0; i != 1u << 31u; ++i )
    		value += i;
    
    	auto time = clock() - first;
    	std::cout << "Time: " << time << " value: " << value << '\n';
    
    	value = 0; first = clock();
    
    	for( auto i : range_impl<unsigned>(0, 1u << 31u ) )
    		value += i;
    
    	time = clock() - first;
    	std::cout << "Time: " << time << " value: " << value << '\n';
    }
    

    Ausgabe, ohne Optimierung versteht sich:

    Time: 5220916 value: 3221225472
    Time: 14310359 value: 3221225472
    

  • Mod

    Abgesehen, dass natürlich die Abbruchbedingung eigentlich Quark ist (1 << 31 ist bei 32-Bit int s im Zweierkomplement 231-2^{31}...), macht das alles keinen Unterschied.
    Keiner benutzt das, solange nicht klar feststeht, das beide immer dieselbe Performance haben. Assembler auf -O2/3 hin oder her. Wie sieht es mit VC++ aus? Optimiert VC++ 2012 das ganze auch so schön wie die neuesten GCC- und Clang-Versionen?



    • schrieb:

    1u << 31u

    lol, lern erst mal C++.


  • Mod

    c++11kiddy schrieb:

    • schrieb:

    1u << 31u

    lol, lern erst mal C++.

    Ja, das ist die korrigierte Version. 1u << 31u entspricht 2312^{31}, einer Zahl die hier groß genug ist, um bei Geschwindigkeitstests sinnvolle Ergebnisse zu bekommen.
    (Schon klar, dass der Suffix beim zweiten Literal keinen Sinn macht, das ist doch völlig irrelevant)

    1 << 31 war auf die Schnelle eingetippt, das ist natürlich Blödsinn.



  • Leute, ich will ja nichts sagen, aber das hat nicht mehr wirklich etwas mit meiner Frage zu tun.
    Ich wäre euch sehr dankbar, wenn ihr das woanders diskutieren könntet.


  • Mod

    BIOSzillator schrieb:

    Leute, ich will ja nichts sagen, aber das hat nicht mehr wirklich etwas mit meiner Frage zu tun.

    Ich dachte, alle Fragen wären beantwortet?

    Was willst du denn noch wissen?



  • Beispielsweise hat ja Knivil gesagt, dass ich zu viele if else Anweisungen verwendet habe.
    Ich frage mich jetzt nur, wie man diese vermeiden kann.

    Mein Programm macht ja nach der for Schleife folgendes.

    Schaue ob num1 und num2 unterschiedlich sind.
    Wenn ja:
    Schaue ob sie höchstens 0.5 auseinander liegen.
    Wenn nein:
    Sage nur, welche die größere und kleinere von beiden ist.
    Wenn alles nicht zutrifft:
    Sage, dass die Zahlen identisch sind.
    

    Mir würde jetzt nur keine Lösung einfallen, wie man diese if und else Abfragen vermeiden oder ersetzen könnte.



  • @ BIOSzillator

    Ich finde deinen Code kann man gut lesen. Spaghetti Code ist das meiner Meinung nach NICHT.



  • BIOSzillator schrieb:

    @Hustbaer

    Ich glaube, dass du einen etwas falschen Eindruck vom Remixen und dem Musik machen ansich hast.
    Vielleicht habe ich deinen Post ja auch nur falsch verstanden, jedoch klingt deine Aussage nach:
    "Kein Musikproduzent weiß was er da macht, denn ansonsten könnte es keine neue Musik mehr geben."

    Nein, du machst den gleichen Fehler wie *.

    Vielleicht hilft ein einfaches Beispiel...

    Aussage 1:
    Franz isst jeden Tag in der Mensa. Bei Sepp ist das anders.

    Daraus kann ich ableiten: Sepp isst nicht jeden Tag in der Mensa.
    Anders formuliert ist das dann: Sepp isst zumindest an einem Tag nicht in der Mensa.

    Die Aussage 2:
    Sepp isst nie in der Mensa.
    kann ich daraus aber nicht ableiten.

    Die Erwiederung:
    Nein, das (Aussage 1) ist falsch, weil ich hab Sepp schon oft in der Mensa essen sehen. Muss er ja auch, weil er schreibt ja ein Mensa-Blog bla bla blaaaaaaaah.
    wäre also totaler Unsinn.
    Und zwar weil der nach "(Aussage 1) ist falsch" folgende Teil keinerlei Bezug zu Aussage 1 hat. Was aber wiederrum nicht bedeutet dass dieser Teil für sich genommen falsch ist.

    Also nochmal: es wurde nie behauptet dass Sepp nie in der Mensa isst. Es wurde nie behauptet dass Musiker nie wissen was sie tun.


  • Mod

    Also nochmal: es wurde nie behauptet dass Sepp nie in der Mensa isst. Es wurde nie behauptet dass Musiker nie wissen was sie tun.

    Nein, aber es wurde demnach behauptet, dass Musiker manchmal nicht wissen was sie tun, was schlicht falsch ist. Auch beim kreativen Part.

    wie *.

    kleene Star.



    • schrieb:

    Also nochmal: es wurde nie behauptet dass Sepp nie in der Mensa isst. Es wurde nie behauptet dass Musiker nie wissen was sie tun.

    Nein, aber es wurde demnach behauptet, dass Musiker manchmal nicht wissen was sie tun, was schlicht falsch ist. Auch beim kreativen Part.

    Ob das schlicht falsch ist oder nicht kommt darauf an wie man die Aussage interpretiert. Da besteht nämlich einiges an Spielraum. Und so wie ich sie verstehe ist sie nicht schlicht falsch. Aber darum geht's mir eigentlich nicht.

    Worum es mir geht: wenn es das ist was du gemeint hast, dann hättest du vielleicht auch das hinschreiben sollen. Und nicht etwas anderes, was zur kritisierten Aussage keinen Bezug hat. Das macht nämlich keinen Sinn.

    • schrieb:

    wie *.

    kleene Star.

    Wenn du kleene Star genannt werden willst, dann hättest du das vielleicht als Username eingeben sollen. Und nicht was anderes.

    Es ergibt sich ein Schema.


Anmelden zum Antworten