Geradzahligkeit ermitteln
-
Das macht der Vc++ 2005 draus (release build):
Shadows Variante:
_is_even PROC ; _num$ = eax ; 4 : return num%2==0; and eax, -2147483647 ; 80000001H jns SHORT $LN3@is_even dec eax or eax, -2 ; fffffffeH inc eax $LN3@is_even: neg eax sbb eax, eax add eax, 1 ; 5 : } ret 0 _is_even ENDPaudacias Variante:
_is_even2 PROC ; _num$ = eax ; 9 : return !(num&1); not eax and eax, 1 ; 10 : } ret 0 _is_even2 ENDPEs wird zwar in der ersten die Division wegoptimiert, aber wirklich schön isses trotzdem nicht.
-
hustbaer schrieb:
Dafür ist sie "geekiger"

Und schöner formatiert. SCNR

-
Modulo-Operationen sind leider immer recht teuer. Da kann der Compiler auch nicht viel dran optimieren.
-
Also bei MOD 2^n kann ein Compiler sehr wohl optimieren.
@vlad_tepesch: Optimierer war auf was eingestellt?
-
Tachyon schrieb:
Modulo-Operationen sind leider immer recht teuer. Da kann der Compiler auch nicht viel dran optimieren.
TS-MacBook-Pro:Code ts$ cat test.c int is_even(int num) { return num % 2 == 0; } int is_even2(int num) { return !(num&1); } TS-MacBook-Pro:Code ts$ gcc -O3 -c test.c -S TS-MacBook-Pro:Code ts$ cat test.s .text .align 4,0x90 .globl _is_even _is_even: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax xorl $1, %eax andl $1, %eax leave ret .align 4,0x90 .globl _is_even2 _is_even2: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax xorl $1, %eax andl $1, %eax leave ret .subsections_via_symbols TS-MacBook-Pro:Code ts$ gcc --version i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5488) Copyright (C) 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.also zumindest mein gcc kann das problemlos optimieren...
-
also zumindest mein gcc kann das problemlos optimieren...
Naja, optimiert ist auch was anderes!
@vlad_tepesch: Optimierer war auf was eingestellt?
Full optimization; Favor fast Code
-
vlad_tepesch schrieb:
Naja, optimiert ist auch was anderes!
Was meinst du?
Zuhause werde ich es dann beim vc++08 mal testen und die ergebnisse posten. kann mir irgendwie nicht vorstellen dass es moderne compiler gibt die so doof sind dass sie das nicht optimieren können.
bei dem von dir geposteten asm code wird sehr komisch herumgerechnet um am ende wieder das selbe zu machen was er bei der anderen version macht:
add eax, 1
-
Shade Of Mine schrieb:
vlad_tepesch schrieb:
Naja, optimiert ist auch was anderes!
Was meinst du?
Das nenn ich optimal:
_is_even2 PROC ; _num$ = eax ; 9 : return !(num&1); not eax and eax, 1 ; 10 : } ret 0 _is_even2 ENDPZuhause werde ich es dann beim vc++08 mal testen und die ergebnisse posten.
Was ich gepostet hatte stammt doch vom vc8.
vlad_tepesch schrieb:
Das macht der Vc++ 2005 draus (release build):
-
bool is_even(int num) { return num%2u==0; }
-
vlad_tepesch schrieb:
Das nenn ich optimal:
_is_even2 PROC ; _num$ = eax ; 9 : return !(num&1); not eax and eax, 1 ; 10 : } ret 0 _is_even2 ENDPVerstehst du den asm Code überhaupt?
Nichts anderes macht der gcc. bits invertieren und dann testen ob das rechteste bit eine 1 ist.ob du dafür not oder xor verwendest ist egal. es wird seinen grund haben warum der gcc hier lieber xor und der vc++ lieber not nimmt.
und nach dem xor/not wird ein and gemacht. fertig.
ich habe dem gcc aber verboten die funktion inline zu definieren so wie du es dem vc++ erlaubt hast - was dazu führt dass der code leicht verfälscht ist, da es schwerer ist die genauen kosten zu berechnen.
deshalb muss bei mir der gcc erst den parameter vom stack popen und in ein register schieben. So kann ich genau die kosten der Funktion erkennen und kann garantieren dass nichts wegoptimiert wird was generell nötig ist aber für den aktuellen fall uninteressant ist.
zB wenn der compiler weiss dass num immer 2 ist, kann er die funktion zu einem
mov eax, 1
machen und fertig. aber das wäre ja doof, deshalb verbiete ich ihm diese optimierungen.
-
Und wie langweilig

camper hat wie immer recht. dumme sache das. mach mal fehler!!PUBLIC _is_even ; Function compile flags: /Ogtpy ; File d:\code\testili\testili\extern.cpp ; COMDAT _is_even _TEXT SEGMENT _num$ = 8 ; size = 4 _is_even PROC ; COMDAT ; 2 : return num%2u == 0; mov eax, DWORD PTR _num$[esp-4] not eax and eax, 1 ; 3 : } ret 0 _is_even ENDP _TEXT ENDS PUBLIC _is_even2 ; Function compile flags: /Ogtpy ; COMDAT _is_even2 _TEXT SEGMENT _num$ = 8 ; size = 4 _is_even2 PROC ; COMDAT ; 6 : return !(num&1); mov eax, DWORD PTR _num$[esp-4] not eax and eax, 1 ; 7 : } ret 0 _is_even2 ENDP _TEXT ENDSsehr dummer vc++ aber. denn er koennte eigentlich wissen dass 2 nicht negativ sein kann...
-
Wirklich sehr dumm, dem VC++ hätte ich schon etwas mehr zugetraut...
Wie ist das eigentlich mit anderen Operationen, z.B. Bitshift bzw. Multiplikation/Division mit 2? Das wäre ja das Letzte, wenn man Performanceeinbusse in Kauf nehmen müsste, weil man keine Bitschiebereien einsetzt.
-
Shade Of Mine schrieb:
sehr dummer vc++ aber. denn er koennte eigentlich wissen dass 2 nicht negativ sein kann...
Das weiß er schon, er weiß aber nicht -kann nicht wissen - dass num nicht negativ sein kann (das kann es ja sehr wohl). 2u deshalb nur, um den ersten Operanden implizit in unsigned zu konvertieren statt einen cast zu bemühen. vc hat ja recht insofern, dass vorzeichenbehaftete Integer-Division, wenn man sie mit shifts baut, für negative Werte anders ausgeführt werden muss (weil arithmetisches Rechtsshift stets abrundet, Division durch eine dagegen immer Richtung 0 bei x86&co) - daher die Unterscheidung. Das ist bei gcc auch nicht anders - nur ist dort der Optimierer offenbar clever genug zu erkennen, dass das in diesem speziellen Fall unerheblich ist. Bleibt noch zu erwähnen für diejenigen, die Assembler nicht verstehen, dass der Compiler audacias Variante in folgendes Äquivalent (2er-Komplement!) transformiert:
inline bool isEven (int num) { return ~num & 1; }