Erkennen von kommastellen

hy, ich suche eine mölichkeit eine zahl die ich durch 2 teile auf die die kommastellen zu untersuchen.

wenn die zahl gerade ist, also ohne kommastellen, dann rückmeldung 1
wenn die zahl eine oder mehr kommastellen hat, dann rückmeldung 2

danke für die hilfe
mein c++ toll = dev c++

marcus

hi marcus,

bei ganzen Zahlen (integern) hilft der % Operator

i%2 liefert den Rest der Division durch 2, also entweder 0 (gerade) oder 1 (ungerade). für Deine Rückmeldung wäre es demnach

((i%2)+1), wobei die Werte 1 und 2 aber unüblich sind falls es sich z.B. eher um Wahr oder Falsch handeln sollte

Gruß
achim

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Abend!

neben der Möglichkeit von Achim kannst du auch folgendes schreiben:
Result = (Zahl & 1) + 1;

Was um Größenordnungen schneller ist.

Gruß
Stefan

ot. Speed
Hallo Stefan,

Deine Lösung ist sicherlich gut und vielleicht sogar ein wenig smarter. Ein Laufzeitunterschied zwischen

Result = (Zahl % 2) + 1;
und
Result = (Zahl & 1) + 1

dürfte bei kommerziellen Compilern hingegen nicht auftreten. Ich würde dies nicht erwähnen, wenn ich nicht schon

a = b >> 2; // perform fast division by 4

im Code gesehen hätte, was auf völlige Unkenntnis der Arbeit von Compilern hindeutet.

Gruß
achim

Hallo Acim & Stefan,

Result = (Zahl % 2) + 1;
und
Result = (Zahl & 1) + 1

„You can’t beat Stefan here“ :wink:

bei mir (VS2005/C++):

Achim

 **int res = (val % 2) + 1;** 
 00411F44 mov eax,dword ptr [val] 
 00411F47 and eax,80000001h 
 00411F4C jns func3+33h (411F53h) 
 00411F4E dec eax 
 00411F4F or eax,0FFFFFFFEh 
 00411F52 inc eax 
 00411F53 add eax,1 
 00411F56 mov dword ptr [res],eax 

[CMБ]

**int res = 1   
 004113B4 mov ecx,dword ptr [val]   
 004113B7 and ecx,1   
 004113BA mov eax,1   
 004113BF shl eax,cl   
 004113C1 mov dword ptr [res],eax**   

Stefan

 **int res = (val & 1) + 1;**
 00411A44 mov eax,dword ptr [val] 
 00411A47 and eax,1 
 00411A4A add eax,1 
 00411A4D mov dword ptr [res],eax 

Also das Bienchen geht meiner Meinung nach an Stefan :wink:

Grüße

CMБ

Ein klitzekleines bißchen polemisch …
… würde ich sagen:

„You can’t beat Stefan here“ :wink:

but Achim’s right too

VS2005/C++

was auf völlige Unkenntnis der Arbeit von Compilern hindeutet.

 :smile:

Eine derartige Optimierung sollte ein Compiler eigentlich „im Unterbewußtsein“ erledigen.

Gruß,
Ralf

Hallo Achim,

Deine Lösung ist sicherlich gut und vielleicht sogar ein wenig
smarter. Ein Laufzeitunterschied zwischen

Result = (Zahl % 2) + 1;
und
Result = (Zahl & 1) + 1

dürfte bei kommerziellen Compilern hingegen nicht auftreten.
Ich würde dies nicht erwähnen, wenn ich nicht schon

a = b >> 2; // perform fast division by 4

Hallo! Das kann ein Compiler nicht ersetzen, das ist nur möglich
wenn man genau weiß in welchem Zahlenbereich man ist, ansonsten
wird das Ergebnis falsch! Ein Compiler dividiert immer, wenn er
nicht 100% genau den Zahlenbereich weiß.

Versuch mal
int t = -1;
t >>=1;

Das Ergebnis ist -1 und das ist nicht t/2.

Gruß
Stefan

[verständliche Polemik]

„You can’t beat Stefan here“ :wink:

but Achim’s right too

VS2005/C++

was auf völlige Unkenntnis der Arbeit von Compilern hindeutet.

Eine derartige Optimierung sollte ein Compiler eigentlich „im
Unterbewußtsein“ erledigen.

Welcher Compiler sollte das sein?

gcc 4.0.2/ -O3 liefert das:

Stefan:

int res = (val & 1) + 1;
 ...
 movl 8(%ebp), %eax
 movl %eax, %edx
**1: andl $1, %edx**
**2: incl %edx**
 pushl %edx
 pushl %eax
 ...

[CMБ]:

int res = 1 1: andl $1, %ecx
**2: sall %cl, %eax**
 pushl %eax
 pushl %edx 
 ...

Achim:

int res = (val % 2) + 1;
 ...
 movl 8(%ebp), %edx
 movl %edx, %ecx
**1: shrl $31, %ecx**
**2: leal (%edx,%ecx), %eax**
**3: andl $1, %eax**
**4: subl %ecx, %eax**
**5: incl %eax**
 pushl %eax
 pushl %edx
 ...

scnr :wink:

CMБ

Hallo CMБ

„You can’t beat Stefan here“ :wink:

Danke für die Blumen.

Das ist unglaublich wie dämlich MikkiSoft sich da anstellt
Ich konnte es gar nicht glauben und habe es auch probiert, mit
dem selben Ergebnis, datt gehampel um das Vorzheichen, woführ?.

Gruß
Stefan

Grau, teurer Freund …
… ist alle Theorie …

[verständliche Polemik]

Ich fühle mich verstanden - Danke.

„You can’t beat Stefan here“ :wink:

but Achim’s right too

VS2005/C++

was auf völlige Unkenntnis der Arbeit von Compilern hindeutet.

Eine derartige Optimierung sollte ein Compiler eigentlich „im
Unterbewußtsein“ erledigen.

Welcher Compiler sollte das sein?

Behufs meinerseitiger Ehrenrettung verweise ich z.B. auf Aho/Sethi/Ullman: Compilerbau, Teil 2 (dt.) ISBN: 3486252666 Buch anschauen, allwo es auf Seite 681 heißt: „Manche Maschinenbefehle sind deutlich billiger als andere und können oft als Spezialfälle von aufwendigeren Operationen benutzt werden.“

Oder, um ein bekanntes Zitat an nicht ganz passender Stelle anzubringen: „Wenn die Realität nicht der Theorie entspricht, umso schlimmer für die Realität.“

Gut’s Nächtle
Ralf

Hallo,

allwo es auf Seite 681 heißt: „Manche Maschinenbefehle sind
deutlich billiger als andere und können oft als Spezialfälle
von aufwendigeren Operationen benutzt werden.“

alle Beteiligten hier wissen das, bloss der Compiler nicht. Ich habe mir früher mal eine Library (in Assembler) geschrieben mit Funktionen wie 16 oder 32 bit OR, AND, XOR usw. die einfach 2 Register mit dem entsprechenden Maschinenbefehl verknüpfen, da weiss ich definitiv, dass die Ausführung optimal ist, egal was sich der Compiler dazu denkt. Letzlich ist das auch nicht mehr Arbeit, als die Ergebnisse des Compilers nachher zu überprüfen, wie hier geschehen. Wenn es wirklich drauf ankommt, vertraue ich eben nur mir selbst und nicht einer so komplexen Software. Man sollte daher auch den/die Assembler nicht einfach für tot erklären.

Gruss Reinhard

Gratulation an den Sieger
Hallo Stefan,

was für eine riesen-Enttäuschung für mich. Ich habe das wirklich nicht für möglich gehalten.

Ich mag als schlechter Verlierer gelten, wenn ich noch anfüge, dass bei mir (Microsoft VC++6) für unsigned int ein identischer Code in beiden Varianten erzeugt wird. Bei int (also da wo es drauf ankommt :smile: liegst Du ja wirklich meilenweit vorn.

Gruß
achim

für den sich wieder einiges entzaubert hat

Ich will auch mal!
Hallo Leute,

Angespornt durch Eure Beiträge untersuchte ich das ganze mit dem Compiler von Borland C++ 6.0:

Achim

 **int res = (val % 2) + 1;**
 004018FE 8B45F8 mov eax,[ebp-0x08]
 00401901 2501000080 and eax,0x80000001
 00401906 7905 jns +0x05
 00401908 48 dec eax
 00401909 83C8FE or eax,-0x02
 0040190C 40 inc eax
 0040190D 40 inc eax
 0040190E 8945FC mov [ebp-0x04],eax

[CMБ]

**int res = 1   
 00401911 8B4DF8 mov ecx,[ebp-0x08]  
 00401914 83E101 and ecx,0x01  
 00401917 BA01000000 mov edx,0x00000001  
 0040191C D3E2 shl edx,cl  
 0040191E 8955FC mov [ebp-0x04],edx**   

Stefan

 **int res = (val & 1) + 1;**
 00401921 8B45F8 mov eax,[ebp-0x08]
 00401024 83E001 and eax,0x01
 00401927 40 inc eax
 00401928 8945FC mov [ebp-0x04],eax 

Der Compiler versucht aber bei Integermultiplikationen durchaus zu optimieren:

**int res = val \* 2;**
 004018FE 8B45F8 mov eax,[ebp-0x08]
 00401901 03C0 add eax,eax
 00401903 8945FC mov [ebp-0x04],eax
**int res = val \* 3;**
 00401906 8B55F8 mov edx,[ebp-0x08]
 00401909 8D1452 lea edx,[edx+edx\*2]
 0040190C 8955FC mov [ebp-0x04],edx
**int res = val \* 4;**
 0040190F 8B4DF8 mov ecx,[ebp-0x08]
 00401912 C1E102 shl ecx,0x02
 00401915 894DFC mov [ebp-0x04],ecx
**int res = val \* 5;**
 00401918 8B45F8 mov eax,[ebp-0x08]
 0040191B 8D0480 lea eax,[eax+eax\*4]
 0040191E 8945FC mov [ebp-0x04],eax
**int res = val \* 6;**
 00401921 8B55F8 mov edx,[ebp-0x08]
 00401924 03D2 add edx,edx
 00401926 8D1452 lea edx,[edx+edx\*2]
 00401929 8955FC mov [ebp-0x04],edx

Einen schönen Tag noch,
Pürsti

Hallo Achim,

… wenn ich noch anfüge,
dass bei mir (Microsoft VC++6) für unsigned int ein
identischer Code in beiden Varianten erzeugt wird.

So unrecht hattest Du ja nicht. Auch bei gcc4
wird bei ‚unsigned‘ identischer Code
(Varianten Achim/Stefan) erzeugt. Daher war
dieser Fall auch für mich sehr aufschlußreich -
unabhängig vom „Wettkampfgedanken“ :wink:

Grüße

CMБ

Hallo Pürsti

Der Compiler versucht aber bei Integermultiplikationen
durchaus zu optimieren:
int res = val * 6;
00401921 8B55F8 mov edx,[ebp-0x08]
00401924 03D2 add edx,edx
00401926 8D1452 lea edx,[edx+edx*2]
00401929 8955FC mov [ebp-0x04],edx

Zumindest dieser Code dürfte auf heutigen Intel CPUs langsamer
sein wie die Multiplikation. Der lea erzeugt einen unnötigen „stall“
und die Gesamtzahl der Op-Code-Bytes ist auch nicht mehr geringer.

Das ist Pentium III Code, leider gibt es keinen Compiler der
neuen CPU Architekturen wirklich gerecht wird.

Gruß
Stefan

Hallo Reinhard,

Wenn
es wirklich drauf ankommt, vertraue ich eben nur mir selbst
und nicht einer so komplexen Software. Man sollte daher auch
den/die Assembler nicht einfach für tot erklären.

Das ist heute sehr, sehr schwer geworden. Früher habe ich komplexe
Routinen in einem bis zwei Tagen in Assembler geschrieben und war
immer doppelt so schnell wie der Compiler. Heute benötige ich für
solche Routinen 14 Tage und erreiche den Faktor 1,5 (wenn ich Glück
habe).
Out-Of-Order-Execution, Branch-Prediktion, Multiple-Code-Prefetching
und so weiter machen es wirklich schwer.
Ich hatte schon ein Tool geschrieben, dass mir „stalls“ aufgrund
zu früher Registerbenutztung anzeigte, seit die Dinger (CPUs) auto
renaming auf Register machen kann man es nun in die Tonne klopfen.

Obwohl Intel es eigentlich besser können müßte hat deren Compiler
gegen MikroSoft keine Chance (i386 wie auch xScale). Der Grund ist
auch klar. Die Jungs von Intel/AMD analysieren existierenden Code
und versuchen ihre CPUs so zu optimieren, das dieser Code schnellst
möglich ausgeführt wird. Da die meisten Programme mit MicroSoft
erzeugt sind arbeiten praktisch die Hardware Intel/AMD Jungs gegen
ihre eigen Software Kollegen.

Gruß
Stefan

Hallo Achim,

was für eine riesen-Enttäuschung für mich. Ich habe das
wirklich nicht für möglich gehalten.

Ich mag als schlechter Verlierer gelten, wenn ich noch anfüge,
dass bei mir (Microsoft VC++6) für unsigned int ein
identischer Code in beiden Varianten erzeugt wird. Bei int
(also da wo es drauf ankommt :smile: liegst Du ja wirklich
meilenweit vorn.

Und das sind sozusagen HighEnd Compiler!
Du hast in deiner Vika stehen, Entwicklung von Firmware/Software von
embedded Systemen, das ist auch der Bereich in dem ich im Moment
hauptsächlich tätig bin. Ich kann dir sagen ich schaue dort jedem
Compiler auf die Finger. Einzig die xScale (ARM) Crosscompiler von
Mikrosoft sind einigermaßen brauchbar. Intel für xScale ist eine
Zumutung, Gnu für Motorola (Coldfire) ist ein Witz, Metaware für
Arc geht gerade so und TI Compiler sind ein Lacher.

Wenn du dann noch anfängst CPUs zu programmieren die innerhalb
eines FPGAs sind (sozusagen die selbst programmierte CPU) dann wirst
du die oben genannten Compiler lieben. Der Hauptkampf besteht dann
nämlich darin die Fehler des Compilers zu umschiffen.

Gruß
Stefan

Ich will auch
Hallo beisammen,
bei mir:
IAR H8/300 & H8/300H C-Compiler V3.50A

Achim

 **int res = (val % 2) + 1;**
00000002 0D65 MOV.W R6,R5
00000004 79060002 MOV.W #2,R6
00000008 17F5 EXTS.L ER5
0000000A 01D05365 DIVXS.W R6,ER5
0000000E 0B5D INC.W #1,E5
00000010 69FD MOV.W E5,@SP

[CMБ]

**int res = 1   
00000002 EE01 AND.B #1,R6L  
00000004 79050001 MOV.W #1,R5  
00000008 1C5E CMP.B R5H,R6L  
0000000A 4706 BEQ ?0000  
0000000C ?0001:  
0000000C 1015 SHLL.W R5  
0000000E 1A0E DEC.B R6L  
00000010 46FA BNE ?0001  
00000012 ?0000:  
00000012 69F5 MOV.W R5,@SP**   

Stefan

**int res = (val & 1) + 1;**
00000002 79660001 AND.W #1,R6
00000006 0B56 INC.W #1,R6
00000008 69F6 MOV.W R6,@SP

MfG Peter(TOO)