Geradzahligkeit ermitteln



  • 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 ENDP
    

    Zuhause 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):


  • Mod

    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 ENDP
    

    Verstehst 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	ENDS
    

    sehr 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.


  • Mod

    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; }
    

Anmelden zum Antworten