Böses Microoptimieren! (Bedingungen)
-
Optimiz0r schrieb:
//oder besser das? char a; switch(a) { case 'a': return 1; break; case 'b': return 2; break; case 'c': return 3; break; case 'A': return 1; break; case 'B': return 2; break; case 'C': return 3; break; }Und bitte kein geflame
Vielleicht
char a; switch(a) { case 'a': return 1; break; case 'b': return 2; break; case 'c': return 3; break; } switch(a) { case 'A': return 1; break; case 'B': return 2; break; case 'C': return 3; break; }oder
char a; switch(to_lower(a)) { case 'a': return 1; break; case 'b': return 2; break; case 'c': return 3; break; }
-
Warum hinter return ein break?
Das sollte eigentlich zu nicht erreichbarem Code zählen oder nicht?
rya.
-
Ja stimmt

-
bevor du jz wieder an volkards sarkasmus scheiterst:
switch(a) { case 'a': case 'A': return 1; case 'b': case 'B': return 2; }sollte die schnellste variante sein ;o) (aber auch hier gilt - wie immer bei solchen fragen - ganz genau kann dir das nur ein profiler zeigen - und dann auch nur für einen bestimmten compiler und eine bestimmte platform - und nicht zu letzt eine bestimmte config
)
ich weiß nur nicht, ob der compiler bei 'Z'-'A' == 26 das ganze zu ner addition(bzw subtraktion) optimieren kann.bb
-
Was für C++ Code in welchen Assembler-Code übersetzt wird, ist total Compiler-abhängig.
Damit erübrigt sich IMO auch schon jegliche Diskussion darüber welche "Schreibweise" für irgendwas "schneller" ist.Was wirklich etwas bringen kann, sind Dinge wie __assume (http://msdn.microsoft.com/en-us/library/1b3fsfxw(VS.80).aspx), oder diverse Compiler-Intrinsics für MMX/SSE/SSE2/...
Und natürlich kann es nie schaden mal etwas an den Compiler-Optionen rumzuschrauben. Inlining für alle Funktionen erlauben, ggf. maximal erlaubte Inlining-Tiefe erhöhen und Link-Time-Code-Generation aktivieren kann z.B. Wunder wirken.
p.S.: natürlich gibt es auch noch profile-guided Optimization. Bringt zwar meistens keine Welten, aber 5% sind schnell mal drin.
-
unskilled schrieb:
bevor du jz wieder an volkards sarkasmus scheiterst:
switch(a) { case 'a': case 'A': return 1; case 'b': case 'B': return 2; }sollte die schnellste variante sein ;o)
noch schneller:
return a & 3;
-
aber eben wieder nur für die annahme, dass 'z'-'a' == 26 == 'Z'-'A' und jetzt so gar noch für 'z' & 3 == 'Z' & 3 == 1
mal davon abgesehen, dass so etwas nie der flaschenhals sein wird, kommts halt drauf an, für was man programmiert - wenns nur "normale" maschinen sind, dann kann man sich wohl auf ASCII verlassen(baut ggf. noch nen static assert ein)...
(ich vertrau dir einfach mal, dass o.g. für ascii gilt^^)bb
-
unskilled schrieb:
bevor du jz wieder an volkards sarkasmus scheiterst:
Hä? Welcher Sarkasmus denn? Ich gehe davon aus, daß es nicht darum geht, nur diese Zahl zu returnen, sondern anhand des Buchstabens unterschiedliche Sachen zu machen und daß Groß- und Kleinbuchstaben als gleich behandelt werden. Von assume gehe ich natürlich mal aus, wollte das nur nicht am Anfang zeigen. Und meine erste Version klingt danach, als könnte ziemlich jeder compiler das optimal übersetzen, ganz im Gegensatz zu den anderen Versionen mit großen Löchern in der Wertetabelle. Um das Riesenloch wegzumachen, spaltete ich ein Lochswitch in zwei gute switch auf. Und die zweite geht von inline int to_lower(int ch){return ch|64;} oder was ähnlich schnellem aus, womit dessen Einsatz zur Beschleunigung sehr wohl gerechtfertigt ist.
unskilled schrieb:
sollte die schnellste variante sein
Warum?
unskilled schrieb:
ich weiß nur nicht, ob der compiler bei 'Z'-'A' == 26 das ganze zu ner addition(bzw subtraktion) optimieren kann.
DAS wäre mal ein Grund für Sarkasmus.
-
Nachdem in ASCII 'A'==0x41 und 'a'==0x61 ... ja, gilt das

Ansonsten:
#if defined(_MSC_VER) && _MSC_VER >= 1400 #define OPTIMIZE_ASSUME(x) __assume(x) #else #define OPTIMIZE_ASSUME(x) ((void)x) #endif // ... switch(a) { case 'a': case 'A': return 1; case 'b': case 'B': return 2; default: OPTIMIZE_ASSUME(false); // never get here }
-
"'Z'-'A' == 26"
25 - sry^^"Warum?"
Weil ich iwas falsch gemacht hatte und somit zu der auffassung gekommen war, dass zumindest der msvc die beiden switchs nicht zusammenfassen kann - aber habs gerad noch ma getestet und er scheint es doch zu können^^MSVC08
int test() { 012819A0 push ecx char tmp; std::cin >> tmp; 012819A1 lea eax,[esp+3] 012819A5 push eax 012819A6 call std::operator>><char,std::char_traits<char> > (12842D0h) switch(tmp) 012819AB movsx ecx,byte ptr [esp+7] 012819B0 lea eax,[ecx-41h] 012819B3 add esp,4 012819B6 cmp eax,3 012819B9 ja $LN9+7 (12819D0h) 012819BB jmp dword ptr (12819E8h)[eax*4] { case 'A': return 1; 012819C2 mov eax,1 case 'D': return 4; } switch(tmp) { case 'a': return 1; case 'b': return 2; case 'c': return 3; case 'd': return 4; default: __assume(0); } } 012819C7 pop ecx 012819C8 ret case 'B': return 2; case 'C': return 3; 012819C9 mov eax,3 case 'D': return 4; } switch(tmp) { case 'a': return 1; case 'b': return 2; case 'c': return 3; case 'd': return 4; default: __assume(0); } } 012819CE pop ecx 012819CF ret case 'D': return 4; } switch(tmp) 012819D0 add ecx,0FFFFFF9Fh 012819D3 jmp dword ptr (12819F8h)[ecx*4] { case 'a': return 1; case 'b': return 2; 012819DA mov eax,2 case 'D': return 4; } switch(tmp) { case 'a': return 1; case 'b': return 2; case 'c': return 3; case 'd': return 4; default: __assume(0); } } 012819DF pop ecx 012819E0 ret case 'c': return 3; case 'd': return 4; 012819E1 mov eax,4 default: __assume(0); } } 012819E6 pop ecx 012819E7 retbb
PS: wenn mans nat ganz vorbildlich machen will, sollte man nat hustbaers makro verwenden, aber ich geh jz besser schlafen^^ gn8