Hallo, was ist wohl in C die einfachste bzw. schnellste Möglichkeit, festzustellen, ob eine ganze Zahl grade oder ungrade ist?
:
Verschoben durch Moderator
1 | if (x & 1) { |
2 | // ungerade
|
3 | } else { |
4 | // gerade oder null
|
5 | }
|
Am einfachsten geht wohl Modulo 2 Modulo liefert den Rest beim Dividieren. Somit also 1 für ungerade und 0 für gerade.
./. schrieb: >> Dividieren > > Wohl kaum. 1 mod 2 = 1 2 mod 2 = 0 3 mod 2 = 1 4 mod 2 = 0 Doch, also das ist ziemlich einfach zum schreiben und (für mich) verständlicher als obige Bitmanipulation. Dass es wahrscheinlich länger zum ausführen braucht sollte bei einem PC-Programm bei solchem Kleinkram eher weniger Probleme machen.
Jan H. schrieb: > Dass es wahrscheinlich länger zum ausführen braucht Tut es nur bei einem wirklich herausragend lausigen C-Compiler. Jeder andere erkennt, worum es bei % 2 geht. Was ist eigentlich "einfacher" daran,
1 | a % 2 |
anstelle von
1 | a & 1 |
zu schreiben? Die gleiche Anzahl von Zeichen, und beide Male ist das Sonderzeichen nur mit der Shifttaste erreichbar.
:
Bearbeitet durch User
Mir liegt es näher, eine mathematische Eigenschaft mit einer mathematischen Funktion zu prüfen, statt mit einer, die auf einem Zahlensystem basiert. Ist aber persönliche Vorliebe.
Jan H. schrieb: > Mir liegt es näher, eine mathematische Eigenschaft mit einer > mathematischen Funktion zu prüfen, statt mit einer, die auf einem > Zahlensystem basiert. Ist aber persönliche Vorliebe. So ein Quatsch. Beides basiert auf den Eigenschaften des zugrundeliegenden Zahlensystems. Das "2er" = bitoperation System deckt die binäre Eigenschaft "gerade/ungerade" besser ab als das Zehnersystem.
Rufus Τ. F. schrieb: > Die gleiche Anzahl von Zeichen, und beide Male ist das Sonderzeichen nur > mit der Shifttaste erreichbar. Das Ergebnis ist freilich verschieden, und folglich auch die Implementierung, wenn negative Werte möglich sind. Bei & ist es +1 bei ungeraden negativen Zahlen, bei % -1. Für den nackten Test ist das natürlich egal.
:
Bearbeitet durch User
Rufus Τ. F. schrieb: > Tut es nur bei einem wirklich herausragend lausigen C-Compiler. Wozu du offenbar auch GCC zählst. ;-) Der dividiert nämlich bei dessen meistgenutzer Optimierungsstufe -Os. Weil kürzer.
Jan H. schrieb: > Mir liegt es näher, eine mathematische Eigenschaft mit einer > mathematischen Funktion zu prüfen, statt mit einer, die auf einem > Zahlensystem basiert. Na dann:
1 | #define iseven(a) (((a) / 2)*2 == (a)) |
:-) Ich glaube, ich muß mal nachschauen, was der GCC da herausoptimiert.
:
Bearbeitet durch User
Mach das bitte. Mich interessiert jetzt nach der Diskussion hier doch jetzt auch was GCC so aus den Vorschlägen macht.
A. K. schrieb: > Der dividiert nämlich bei dessen meistgenutzer Optimierungsstufe -Os. > Weil kürzer. PS: Das bezog sich auf AVR.
1 | int f(int a) |
2 | {
|
3 | return a % 2; |
4 | }
|
% bei -O1:
1 | andi r18,1 |
2 | andi r19,128 |
3 | tst r19 |
4 | brge .L2 |
5 | subi r18,1 |
6 | sbc r19,__zero_reg__ |
7 | ori r18,254 |
8 | ori r19,255 |
9 | subi r18,-1 |
10 | sbci r19,-1 |
11 | .L2: |
% bei -Os:
1 | ldi r22,lo8(2) |
2 | ldi r23,0 |
3 | rcall __divmodhi4 |
& bei -Os/-O1:
1 | andi r18,1 |
2 | clr r19 |
:
Bearbeitet durch User
A. K. schrieb: > % bei -Os: ldi r22,lo8(2) > ldi r23,0 > rcall __divmodhi4 > ret Das sieht ja auf den ersten Blick aus wie ein Riesen-Unterschied. Aber wie sieht __divmodhi4 aus? Wie lang ist die? Und dann vergleiche bitte nochmal mit -O1...
?!? schrieb: > Das sieht ja auf den ersten Blick aus wie ein Riesen-Unterschied. Aber > wie sieht __divmodhi4 aus? Wie lang ist die? Der Compiler berücksichtigt bei solchen Entscheidungen nur die Länge des unmittelbar erzeugten Codes, nicht die Länge von dadurch herangezogenen Laufzeitfunktionen.
:
Bearbeitet durch User
1 | int_fast8_t iseven(int_fast8_t a) |
2 | {
|
3 | return (((a) / 2)*2 == (a)); |
4 | }
|
5 | |
6 | |
7 | #define ISEVEN(a) (((a) / 2)*2 == (a))
|
8 | |
9 | |
10 | int main(void) |
11 | {
|
12 | % ... viel anderer Kram |
13 | int8_t a = MCUCSR, b1, b2; |
14 | b1 = iseven(a); |
15 | b2 = ISEVEN(a); |
16 | printf("b1=%i,b2=%i",b1,b2); |
17 | |
18 | |
19 | }
|
ergibt: [a] int8_t a = MCUCSR, b1, b2; 3f4e: 84 b7 in r24, 0x34 ; 52 int_fast8_t iseven(int_fast8_t a) { return (((a) / 2)*2 == (a)); 3f50: 28 2f mov r18, r24 3f52: 87 ff sbrs r24, 7 3f54: 02 c0 rjmp .+4 ; 0x3f5a <main+0x38> 3f56: 21 e0 ldi r18, 0x01 ; 1 3f58: 28 0f add r18, r24 3f5a: 25 95 asr r18 3f5c: 22 0f add r18, r18 3f5e: 33 0b sbc r19, r19 3f60: 99 27 eor r25, r25 3f62: 87 fd sbrc r24, 7 3f64: 90 95 com r25 3f66: 41 e0 ldi r20, 0x01 ; 1 3f68: 50 e0 ldi r21, 0x00 ; 0 3f6a: 28 17 cp r18, r24 3f6c: 39 07 cpc r19, r25 3f6e: 09 f0 breq .+2 ; 0x3f72 <main+0x50> 3f70: 40 e0 ldi r20, 0x00 ; 0 encoder_init(); // Drehgeber int8_t a = MCUCSR, b1, b2; b1 = iseven(a); b2 = ISEVEN(a); printf("b1=%i,b2=%i",b1,b2); 3f72: 5f 93 push r21 3f74: 4f 93 push r20 3f76: 5f 93 push r21 3f78: 4f 93 push r20 3f7a: 8e ee ldi r24, 0xEE ; 238 3f7c: 90 e0 ldi r25, 0x00 ; 0 3f7e: 9f 93 push r25 3f80: 8f 93 push r24 3f82: 0e 94 35 20 call 0x406a ; 0x406a <printf> [/a] bei -Os. Sehr interessant die sehr unterschiedliche Optimierung.
Walter T. schrieb: > Sehr interessant die sehr unterschiedliche Optimierung. Erschreckend, daß Compiler immer noch genau so strohdoof sind wie vor 30 Jahren (Optimierungsanalyse war meine Studienarbeit), aber grossmäulig ständig mit angeblichen superneuen Spitzenoptimierungen angepriesen werden.
A. K. schrieb: > Der Compiler berücksichtigt bei solchen Entscheidungen nur die Länge des > unmittelbar erzeugten Codes, nicht die Länge von dadurch herangezogenen > Laufzeitfunktionen. Sorry, aber das verstehe ich jetzt nicht ganz. Heißt das, daß eine aufgerufene Funktion mit z.B. 500 Zeilen Code vom Compiler als kürzer angesehen wird, weil die eigentliche Funktion gar nicht mitgezählt wird, sondern nur der Aufruf dieser Funktion? Da hab ich bestimmt einen Denkfehler, aber ich habe deine Aussage so verstanden. Korrigiere mich bitte!
Michael B. schrieb: > Erschreckend, daß Compiler immer noch genau so strohdoof sind wie vor 30 > Jahren (Optimierungsanalyse war meine Studienarbeit), aber grossmäulig > ständig mit angeblichen superneuen Spitzenoptimierungen angepriesen > werden. Sehr erschreckend, dass jemand, der Optimierungsanalyse als Studienarbeit hatte, nicht erkennt, dass Optimierung auf Platz das Ziel hat, kürzeren Code zu erzeugen. Wenn der Aufruf der Laufzeitfunktion erheblich kürzer ist, dann ist das in diesem Sinn legitim.
:
Bearbeitet durch User
gerade schrieb: > Jan H. schrieb: >> Mir liegt es näher, eine mathematische Eigenschaft mit einer >> mathematischen Funktion zu prüfen, statt mit einer, die auf einem >> Zahlensystem basiert. Ist aber persönliche Vorliebe. > > So ein Quatsch. Beides basiert auf den Eigenschaften des > zugrundeliegenden Zahlensystems. Und dann versuch mal, binäre Operationen auf floating Point anzusetzen. In modernen Sprachen ist nicht klar, daß Zahlen Integer sind. Einfach hinschreiben, was man wirklich meint, und dann klapts in jeder Sprache. Geht natürlich der Coolnessfaktor "ich weiß wie das Teil innen funktioniert" verloren. MfG Klaus
?!? schrieb: > Da hab ich bestimmt einen Denkfehler, aber ich habe deine Aussage so > verstanden. Korrigiere mich bitte! Richtig erfasst. Nur weiss der Compiler an der Stelle, an der diese Optimierung durchgeführt wird, nicht, wie gross die Laufzeitfunktion ist und auch nicht, wie oft sie aufgerufen wird. Wird diese int/int Division im gesamten Programm nur einmal verwendet, dann ist die Bilanz ungünstig. Wird sie 1000x aufgerufen, dann liegt er aber sowas von richtig.
Michael B. schrieb: > Erschreckend, daß Compiler immer noch genau so strohdoof sind wie vor 30 > Jahren (Optimierungsanalyse war meine Studienarbeit), aber grossmäulig > ständig mit angeblichen superneuen Spitzenoptimierungen angepriesen > werden. Anderer Test, anderer Code ;-)
1 | int f(int a, int b, int c) |
2 | {
|
3 | if (a % 2) |
4 | return b; |
5 | else
|
6 | return c; |
7 | }
|
mit -Os:
1 | mov r25,r23 |
2 | sbrc r24,0 |
3 | rjmp .L2 |
4 | mov r22,r20 |
5 | mov r25,r21 |
6 | .L2: |
7 | mov r24,r22 |
Es hängt schon ein wenig vom Kontext ab, was für Code produziert wird. Ganz so blöd ist GCC nämlich auch wieder nicht. Bei meinem Testcode oben hatte er keine Chance. Das hättest du als erklärter Kenner von Compilern eigentlich erkennen müssen.
:
Bearbeitet durch User
Klaus schrieb: > Einfach hinschreiben, was man wirklich meint, und dann klapts in jeder > Sprache. Eben. Ausnahmen bestätigen zwar die Regel, aber das sind dann meist kompliziertere Fälle. Im konkreten Beispiel klappt es jedenfalls ohne Verrenkungen:
1 | #include <stdbool.h> |
2 | |
3 | bool odd(int x) { |
4 | return x % 2 != 0; |
5 | }
|
Der AVR-GCC liefert bei -O1, -O2, -O3 oder -Os:
1 | odd: |
2 | andi r24,lo8(1) |
3 | ret |
Streitet Euch nicht und laßt auch mal 5 gerade sein. ;-) MfG Paul
Michael B. schrieb: > Erschreckend, daß Compiler immer noch genau so strohdoof sind wie vor 30 > Jahren (Optimierungsanalyse war meine Studienarbeit), Dann reich doch einfach mal einen entsprechenden Patch ein. Kann ja für dich als Super-Duper-1337H4x00R nicht so schwer sein...
:
Bearbeitet durch User
Paul B. schrieb: > Streitet Euch nicht und laßt auch mal 5 gerade sein. Da wird der Code aber viel umständlicher:
1 | bool odd(int x) { |
2 | return x % 2 != 0 && x != 5; |
3 | }
|
1 | sbrs r24,0 |
2 | rjmp .L5 |
3 | ldi r18,lo8(1) |
4 | ldi r19,0 |
5 | sbiw r24,5 |
6 | brne .L4 |
7 | ldi r18,0 |
8 | ldi r19,0 |
9 | .L4: |
10 | mov r24,r18 |
11 | mov r25,r19 |
12 | ret |
13 | .L5: |
14 | ldi r24,0 |
15 | ldi r25,0 |
A. K. schrieb: > Da wird der Code aber viel umständlicher: :-)) Wunderbar! Ein "C"-Programmierer mit Humor. Danke, daß Du das Assembler-Resultat mit drangehangen hast, damit ich sehen konnte, wie Du die 5 "beschützt" hast. mfG Paul
Klaus schrieb: > Einfach hinschreiben, was man wirklich meint, und dann klapts in jeder > Sprache. Du schreibst in beiden Fällen nicht hin, was du meinst.
Jan H. schrieb: > Mir liegt es näher, eine mathematische Eigenschaft mit einer > mathematischen Funktion zu prüfen, statt mit einer, die auf einem > Zahlensystem basiert. Ist aber persönliche Vorliebe. Das kann aber beim Programmieren total in die Irre führen. Mathematisch ist es korrekt (und zeitgemäss) zu fragen, ob die Zahl zur Menge der geraden oder zur Menge der ungeraden Zahlen gehört. Blöd nur, dass beide Mengen unendlich sind (was einen Mathematiker überhaupt nicht stört, einen Computer aber schon). Georg
Rolf M. schrieb: > Du schreibst in beiden Fällen nicht hin, was du meinst. Die Modulo-Methode nutzt aber eine mathematische Eigenschaft der geraden Zahlen und ist damit deutlich näher an der eigentlichen Fragestellung als die Bit-Anguck-Methode, die die Art, in der Zahlen im Speicher repräsentiert werden, ausnutzt und die Frage nur implizit beantwortet.
> int_fast8_t iseven(int_fast8_t a) > { > return (((a) / 2)*2 == (a)); > } Ich beglueckwuensche den Schreiber zu der mit Abstand dussligsten Variante.
Tom schrieb: > als die Bit-Anguck-Methode, die die Art, in der Zahlen im Speicher > repräsentiert werden, ausnutzt und die Frage nur implizit beantwortet. Sollte jemand mal auf die mittlerweile recht exotische Idee kommen, Integers im Einerkomplement darzustellen, wird er die Bitvariante bei negativen Werten nicht nutzen können. Es gab aber eine Zeit, da war diese Darstellung nicht unüblich.
... schrieb: > Ich beglueckwuensche den Schreiber zu der mit Abstand dussligsten > Variante. Ein Zeichen für absolute Phantasielosigkeit. Da ist noch deutlich mehr drin:
1 | int isodd(int a) |
2 | {
|
3 | char buf[7]; |
4 | int n; |
5 | n = snprintf_P(buf,6,PSTR("%i"),a); |
6 | return buf[--n]=='1'; |
7 | }
|
So versteht es selbst ein Grundschüler.
:
Bearbeitet durch User
>> int isodd(int a)
Der Funktionsname 'isnoteven' dürfte aussagekräftiger sein.
A. K. schrieb: > Sehr erschreckend, dass jemand, der Optimierungsanalyse als > Studienarbeit hatte, nicht erkennt, dass Optimierung auf Platz das Ziel > hat, kürzeren Code zu erzeugen. Und warum erzeugt der Compiler dann nicht den andi r18,1 clr r19 ? Ist doch kurz, kürzer als alle beiden anderen.
ZehUndUnd schrieb: > Der Funktionsname 'isnoteven' dürfte aussagekräftiger sein. Die Funktionsnamen sind sowieso ein interessanter Punkt. Als alter Matlab-Nutzer wären mir als erstes die Namen "isodd"/"iseven" eingefallen. Oben fiel auch schon der Name "odd" - das klingt für mich deutlich C-mäßiger (da ein bischen kryptischer). Für den AVR wäre dann noch eine Funktion "oddi8" oder "oddu8" fällig. Von Funktionen, die nur direkt Flash-Konstanten unterstützen ("oddi8_P" und oddu8_P") würde ich allerdings absehen. Der langen Scherze kurzer Sinn: Wie würde ein langjähriger C-Veteran eine solche Funktion überhaupt nennen?
:
Bearbeitet durch User
Michael B. schrieb: > Und warum erzeugt der Compiler dann nicht den > Ist doch kurz, kürzer als alle beiden anderen. Ist kurz aber falsch. -3 % 2 ist -1, nicht +1. Und bei aller Liebe zu Optimierung - es sollte schon das richtige Ergebnis rauskommen. Mein Code verlangte nach dem Ergebnis von a % 2, Yalus aber nach dem von (a % 2) != 0. Das ist der entscheidende Unterschied, der bei Yalu dem Optimizer erlaubt, auf das Vorzeichen zu scheissen.
:
Bearbeitet durch User
Walter T. schrieb: > Wie würde ein langjähriger C-Veteran eine solche Funktion überhaupt > nennen? Für deine Varianten gefiele mir "isOdd" sehr gut, für beide. Allein schon der sprachlichen Zweideutigkeit wegen. ;-)
:
Bearbeitet durch User
A. K. schrieb: > Ist kurz aber falsch. -3 % 2 ist -1, nicht +1. Spielt, bei einer Auswertung durch if, aber keine Rolle, und das auszugucken sollte einen Compiler nicht überfordern.
Michael B. schrieb: > Spielt, bei einer Auswertung durch if, aber keine Rolle, und das > auszugucken sollte einen Compiler nicht überfordern. Dummerweise war in meinem Code aber weit und breit kein "if" zu sehen. Das war ein typischer Testcase einer einzelnen Operation. Minimiert auf die Essenz, isoliert in einer entsprechenden Funktion. Da hat der Compiler keinerlei Chance, irgendwas aus dem ihn nicht bekannten Kontext zu erschliessen. Hintergrund: Shifts/Maskierungen werden ziemlich regelmässig als faktisch äquivalent zu div/mod mit Zweierpotenz gesehen. Das ist so verbreitet, dass es manche dann erstaunt, wenn es dank möglicher negativer Werte nicht so ist und es dann je nach Kontext und Zielmaschine böse Laufzeitauswirkung hat (arm-gcc verhält sich anders). Die Methode, Eigenschaften in einzelne Zwergfunktionen auszulagern, ist nicht ganz so exotisch. Teils eine Stilfrage ist das bei C++ sehr verbreitet, und nicht immer inlined.
:
Bearbeitet durch User
Walter T. schrieb: > Die Funktionsnamen sind sowieso ein interessanter Punkt. Als alter > Matlab-Nutzer wären mir als erstes die Namen "isodd"/"iseven" > eingefallen. Oben fiel auch schon der Name "odd" - das klingt für mich > deutlich C-mäßiger (da ein bischen kryptischer). Für den AVR wäre dann > noch eine Funktion "oddi8" oder "oddu8" fällig. Von Funktionen, die nur > direkt Flash-Konstanten unterstützen ("oddi8_P" und oddu8_P") würde ich > allerdings absehen. > > Der langen Scherze kurzer Sinn: > > Wie würde ein langjähriger C-Veteran eine solche Funktion überhaupt > nennen? Auf jeden Fall nicht iseven oder isodd, da diese Namen verboten sind.
Walter T. schrieb: > Für den AVR wäre dann > noch eine Funktion "oddi8" oder "oddu8" fällig. Für die Zeit vor Weihnachen wünsche ich mir "odduFröhliche!" mfG Paul
Rufus Τ. F. schrieb: > Rolf M. schrieb: >> Auf jeden Fall nicht iseven oder isodd, da diese Namen verboten sind. > > Durch wen? Apple. Das i am Wortanfang ist ein eingetragenes Warenzeichen. Oder war es Intel? iSeven ist doch deren leistungsfähigster Prozessor ;-)
Rufus Τ. F. schrieb: > Rolf M. schrieb: >> Auf jeden Fall nicht iseven oder isodd, da diese Namen verboten sind. > > Durch wen? ISO C.
Dussel schrieb: >>> Auf jeden Fall nicht iseven oder isodd, da diese Namen verboten sind. >> >> Durch wen? Isnichwahr! https://www.youtube.com/watch?v=r3LniM4pQ-A >> Für die Zeit vor Weihnachen wünsche ich mir "odduFröhliche!" A. K. schrieb: > Mit Umlaut? Ach ja -das ist ja "C", das war in manchen Sachen als Kind schon anders. ;-) mfG Paul
Dussel schrieb: > Rufus Τ. F. schrieb: >> Rolf M. schrieb: >>> Auf jeden Fall nicht iseven oder isodd, da diese Namen verboten sind. >> >> Durch wen? > Apple. Das i am Wortanfang ist ein eingetragenes Warenzeichen. Oder war > es Intel? iSeven ist doch deren leistungsfähigster Prozessor ;-) D. h. man muss die Forumspfeifen mit Diot anreden?
ZehUndUnd schrieb: > D. h. man muss die Forumspfeifen mit Diot anreden? Da Warenzeichen auf Produktbereiche bezogen sind, wär das nur der Fall, wenn Apple das auch für den Bereich von (geistiger) Gesundheit angemeldet hat, oder eine Verwechselbarkeit gegeben ist (mit der eigenen Kundschaft?).
:
Bearbeitet durch User
A. K. schrieb: > ZehUndUnd schrieb: >> D. h. man muss die Forumspfeifen mit Diot anreden? > > Da Warenzeichen auf Produktbereiche bezogen sind, wär das nur der Fall, > wenn Apple das auch für den Bereich von (geistiger) Gesundheit > angemeldet hat, oder eine Verwechselbarkeit mit der eigenen kundschaft > nicht auszuschlissen ist. Ist aus deinen Ausführungen u. U. ein kleiner Vorbehalt gegenüber Apple herauszulesen?
Bei allem Tanz um den Namen: Ich nehme also eine Integerzahl, konvertiere sie in Text und prüfe ob die letzte Ziffer eine '1' ist. "%i" formatiert Integer als eine ganz normale Dezimalzahl. Wo ist also die Prüfung auf 3, 5, 7 und 9? Nich sind 40% aller Ergebnisse falsch!
ZehUndUnd schrieb: > Ist aus deinen Ausführungen u. U. ein kleiner Vorbehalt gegenüber Apple > herauszulesen? Aber nicht doch! Ich freu mich nur auf ein diesbezügliches Gerichtsverfahren. Weil ja irgendwo eine Verwechselungsmöglichkeit bestehen müsste. Dafür kämen ja nur die Firmenmitarbeiter oder die Kundschaft in Frage.
:
Bearbeitet durch User
deshalb schreibt man ja auch in Assembler 8-D oder ok für die C Freaks, INLINE Assembler.
Rolf M. schrieb: > ISO C. Ich habe ja durchaus versucht, irgendwas derartiges zu finden -- bitte nenne doch mal die Stelle im Standard, die isodd/iseven verbietet. Im Draft für C-99 tauchen weder isodd noch iseven auf, und das sieht im Draft für C-11 (N1570) nicht anders aus.
POSIX reserviert einige Namen, damit gewisse Bibliotheksfunktionen erweitert werden können. Damit es z.B. keine Kollisionen mit den Funktionen in ctype.h (isalpha,isdigit usw) gibt, sollen z.B. keine Namen mit "is" beginnen. Diese Einschränkung gibt es bei ISO-C selbst m.W. nicht.
marco schrieb: > Diese Einschränkung gibt es bei ISO-C selbst m.W. nicht. Doch. Die kommt eigentlich da her. Rufus Τ. F. schrieb: > Im Draft für C-99 tauchen weder isodd noch iseven auf, und das sieht im > Draft für C-11 (N1570) nicht anders aus. Das liegt daran, daß es nicht explizit um diese Identifier geht, sondern um alle, die mit "is" gefolgt von einem Kleinbuchstaben anfangen. Diese sind reserviert für zukünftige Erweiterungen der Standardbibliothek. Das gilt übrigens nicht nur für Namen, die mit "is" anfangen, sondern auch für "to" und "str". Zu finden ist das in C99 im Kapitel 7.26 "Future library directions".
Rolf M. schrieb: > Zu finden ist das in C99 im Kapitel 7.26 "Future library directions". (Um das zu finden, reicht die von mir verwandte simple Volltextsuche natürlich nicht) Danke!
Der Name tut nicht zur Sache, denn die Funktion hat ein anderes Problem: sie funktioniert nicht!
Bastler schrieb: > Der Name tut nicht zur Sache, denn die Funktion hat ein anderes Problem: > sie funktioniert nicht! Auf welche Funktion beziehst du dich?
Jan H. schrieb: > Mir liegt es näher, eine mathematische Eigenschaft mit einer > mathematischen Funktion zu prüfen, statt mit einer, die auf einem > Zahlensystem basiert. Ist aber persönliche Vorliebe. Ja. Persönliche Vorlieben zählen gelegentlich mehr als der Rest der Welt. Der eigentliche Punkt ist jedoch ein wenig anders. Wir haben es hier definitionsgemäß mit Integerzahlen zu tun, oder versuchst du gar, einer Gleitkommazahl eine Eigenschaft Gerade/Ungerade zuzuordnen? 2.0000 ist gerade, 1.99999999999987 ist dann was? oder 1.23456789E68 ? Und wo soll die Grenze sein? Also. Wir haben Integerzahlen. Basta. Dort hat ein jedes Bit eine festgelegte Wertigkeit und eines dieser Bits hat die Wertigkeit 2^0, also 1. Für die Eigenschaft Gerade oder Ungerade ist das Prüfen genau dieses Bits das eigentliche Kriterium. Das Gerede von "Prüfung mit mathematischen Funktionen" ist in diesem Lichte nur Gebabbel. W.S.
> Auf welche Funktion beziehst du dich?
Auf "isodd()", darum wird doch hier getanzt.
W.S. schrieb: > Dort hat ein jedes Bit eine festgelegte Wertigkeit und > eines dieser Bits hat die Wertigkeit 2^0, also 1. Für > die Eigenschaft Gerade oder Ungerade ist das Prüfen > genau dieses Bits das eigentliche Kriterium. Ahh ja. (-2 mod 2) ist in der üblichen Standard-Mathematik gleich Null; mithin ist -2 gerade. Nachlesbar in jedem Mathe-Buch. Bitte erläutere, wie das mit der Prüfung des LSB korrespondiert, wenn auf der gewählten Plattform Integerzahlen in Einerkomplement- darstellung (!!) codiert sind. Vielen Dank im Voraus.
Bastler schrieb: > Wo ist also > die Prüfung auf 3, 5, 7 und 9? Nich sind 40% aller Ergebnisse falsch! Das macht nichts. In 90% aller unit-Tests würde die Funktion bestehen. Es würde getestet auf 0, 1, -1 und 32768. Rolf M. schrieb: > Das liegt daran, daß es nicht explizit um diese Identifier geht, sondern > um alle, die mit "is" gefolgt von einem Kleinbuchstaben anfangen. Diese > sind reserviert für zukünftige Erweiterungen der Standardbibliothek. Das > gilt übrigens nicht nur für Namen, die mit "is" anfangen, sondern auch > für "to" und "str". > Zu finden ist das in C99 im Kapitel 7.26 "Future library directions". Solche interessanten Schnipsel sind der Grund, warum ich auch sinnlos-Diskussionen so gerne weiterverfolge. Ich hätte eine derartige Funktion (von der Implementierung mal abgesehen) vermutlich tatsächlich je nach Tageslaune "iseven" oder "isEven" genannt.
A. K. schrieb: > Dummerweise war in meinem Code aber weit und breit kein "if" zu sehen. Dummerweise bist du nicht das Mass aller Dinge. Gefragt war nach dem bool'schen Ergebnis ob eine Zahl gerade oder ungerade ist. Da ist eine -1 oder 1 als Ergebnis in C vollkommen egal. Ausserdem weiss der Compiler welche Zahl mod ist, nämlich 2, und kennt den Typ der hingehenden Zahl, das könnte ja unsigned sein. Wie man's dreht und wendet, alle sind klüger als du.
> wenn auf der gewählten Plattform Integerzahlen in Einerkomplement- > darstellung (!!) codiert sind. Einerkomplement ist heute praktisch irrelefant.
Walter T. schrieb: > Wie würde ein langjähriger C-Veteran eine solche Funktion überhaupt > nennen?
1 | fast_int8_t fast_int8_t_promoted_to_int_equals_fast_int8_t_promoted_to_int_divided_by_two_multiplied_by_two_as_fast_int8_t (fast_int8_t a) |
2 | {
|
3 | return (a / 2) * 2 == a; |
4 | }
|
Viel besser ist aber die Umsetzung von a in Z ist gerade <==> a in 2·Z <==> existiert k in Z so dass a = 2 * k. Hier also die ultimative Lösung (C99):
1 | #include <stdbool.h> |
2 | #include <limits.h> |
3 | |
4 | bool iseven (int a) |
5 | {
|
6 | bool even = false; |
7 | int k = INT_MIN; |
8 | |
9 | while (true) |
10 | {
|
11 | // Avoid C's undefined behavior on signed overflow!
|
12 | // Only perform 2 * k if it won't overflow.
|
13 | if (k >= INT_MIN / 2 && k <= INT_MAX / 2) |
14 | if (a == 2 * k) |
15 | even = true; |
16 | if (k == INT_MAX) |
17 | break; |
18 | else
|
19 | k++; |
20 | }
|
21 | |
22 | return even; |
23 | }
|
...damit unsere Compiler-Optimatoren wie Michael ein bisschen was zu kniffeln haben. Wenn deine Optimierungen dann "a & 1" liefern, dann bist du *echt* gut!
Rolf M. schrieb: > Klaus schrieb: >> Einfach hinschreiben, was man wirklich meint, und dann >> klapts in jeder Sprache. > > Du schreibst in beiden Fällen nicht hin, was du meinst. Doch. Gerade Zahlen sind, wenn mich die Reste meiner Mathekenntnisse nicht trügen, so definiert, dass sie bei Division durch 2 den Rest Null lassen ( = sich ohne Rest teilen lassen). In Zeichen: N mod 2 = 0.
Michael B. schrieb: > Gefragt war nach dem > bool'schen Ergebnis ob eine Zahl gerade oder ungerade ist. Da ist eine > -1 oder 1 als Ergebnis in C vollkommen egal. Und genau dann erzeugt der Compiler aus (a % 2) != 0 oder if(a % 2) optimalen Code. Warum hattest du dich dann über den Compiler so bitter beschwert?
:
Bearbeitet durch User
... schrieb: >> wenn auf der gewählten Plattform Integerzahlen in >> Einerkomplementdarstellung (!!) codiert sind. > > Einerkomplement ist heute praktisch irrelefant. Dein Einwand ist irrelevant. Du hast das Problem nicht verstanden. "mod" basiert direkt auf der DEFINITION der geraden Zahl und muss damit auf jeder Plattform und mit jeder beliebigen internen Darstellung von Ganzzahlen korrekt funktionieren. Die Lösung mit "&" hängt von der internen Zahldarstellung ab.
Possetitjel schrieb: > Die Lösung mit "&" hängt von der internen Zahldarstellung ab. Und woher bitte hast du dieses "Wissen"? § 6.2.6 Representations of types § 6.2.6.1 General .3 Values stored in unsigned bit-fields and objects of type unsigned char shall be represented using a pure binary notation. *) *) A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive bits are additive, begin with 1, and are multiplied by successive integral powers of 2, except perhaps the bit with the highest position. (Adapted from the American National Dictionary for Information Processing Systems.) A byte contains CHAR_BIT bits, and the values of type unsigned char range from 0 to 2^CHAR_BIT - 1. § 6.2.6.2 Integer types .1 For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N value bits, each bit shall represent a different power of 2 between 1 and 2^{N-1}, so that objects of that type shall be capable of representing values from 0 to 2^N - 1 using a pure binary representation; this shall be known as the value representation. The values of any padding bits are unspecified.
:
Bearbeitet durch User
Possetitjel schrieb: > Die Lösung mit "&" hängt von der internen Zahldarstellung > ab. Bitte nenne uns eine Integer-Darstellung, bei der das geringstwertige Bit NICHT die Wertigkeit 2^0 hat. Und das möglichst ohne endloses Rumgelabere. Georg
Johann L. schrieb: > Possetitjel schrieb: >> Die Lösung mit "&" hängt von der internen Zahldarstellung ab. > > Und woher bitte hast du dieses "Wissen"? > > § 6.2.6 Representations of types > > § 6.2.6.1 General > > .3 Values stored in unsigned bit-fields and objects of type unsigned > char shall be represented using a pure binary notation. […] > > § 6.2.6.2 Integer types > > .1 For unsigned integer types other than unsigned char, […] Das n & 1 liefert zwar für nichtnegative Werte das gewünschte Ergebnis, nicht aber für negative Werte in Einerkomplementdarstellung. n % 2 != 0 hingegen funktioniert immer. Hier sind übrigens noch zwei weitere, funktional angehauchte Einzeiler für odd und even (welches ich aus ästhetischen Gründen in evn umbenannt habe):
1 | bool odd(int n); |
2 | |
3 | bool evn(int n) { return n == 0 || odd(n + (n<0) - (n>0)); } |
4 | |
5 | bool odd(int n) { return n != 0 && evn(n + (n<0) - (n>0)); } |
Auch diese Funktionen vermag der GCC nicht auf eine oder zwei Assembler- Instruktionen zu reduzieren, aber immerhin löst er (mit -O2) die Rekursion auf, so dass auch bei großen Argumenten kein Stack-Überlauf entsteht.
:
Bearbeitet durch Moderator
Georg schrieb: > Possetitjel schrieb: >> Die Lösung mit "&" hängt von der internen Zahldarstellung >> ab. > > Bitte nenne uns eine Integer-Darstellung, bei der das > geringstwertige Bit NICHT die Wertigkeit 2^0 hat. > > Und das möglichst ohne endloses Rumgelabere. Falls Du vorhast, es demnächst mal mit Höflichkeit zu versuchen, können wir uns unterhalten. Tschüss bis dahin.
Johann L. schrieb: >> Die Lösung mit "&" hängt von der internen Zahldarstellung ab. > > Und woher bitte hast du dieses "Wissen"? Dass das immer funktioniert, ist gar nicht die Frage. Der Unterschied besteht darin, ob man sich innerhalb der Abstraktionsebene des eigentlichen Problems bewegt: "Zahl ist gerade, wenn Zahl mod 2 gleich Null ist." Oder ob man die Frage, die auf der "mathematischen" Ebene (ganze Zahlen) angeordnet ist, beantwortet, indem man einen Umweg über die tiefere Ebene der internen Zahldarstellung geht: "Zahl ist gerade, wenn [hier gedanklich eine Ebene tiefer schalten in den Bereich der Bits] die letzte Stelle der binären Darstellung 0 ist." Ob man diesen Ebenunterschied überhaupt versteht/wahrnimmt, und, falls ja, ob man das abstraktionsebenenübergreifende Programmieren als unnötige Komplexität oder als natürlich empfindet, ist von Person zu Person sehr verschieden. Grüße aus dem Elfenbeinturm ;)
Tom schrieb: > Johann L. schrieb: >>> Die Lösung mit "&" hängt von der internen Zahldarstellung >>> ab. >> >> Und woher bitte hast du dieses "Wissen"? > > Dass das immer funktioniert, ist gar nicht die Frage. Häh? Sagt mal, Leute, LEST ihr manchmal auch, worum's geht? Weiter oben ging es darum, dass man bei --> NEGATIVEN <-- Zahlen, die in --> EINERKOMPLEMENT-DARSTELLUNG <-- vorliegen, NICHT durch verUNDen bestimmen kann, ob die Zahl gerade ist oder nicht. ES FUNKIONIERT NICHT! ES KOMMT DAS FALSCHE HERAUS! "+2" sieht irgendwie so aus: "...000010" "-2" sieht im Einerkomplement so aus: "...111101" Klingelt's?
Ist das eventuell ein Grund (neben deutlich wichtigeren), warum 2-er Komplement beliebter ist? Der Elfenbeinturm ist scheinbar auch zum Schutz der Anderen da.
Nur mal eine Frage nebenbei: Wird die Einerkomplement-Darstellung überhaupt irgendwo angewendet? Eine Darstellung, die zwei Darstellungen der Zahl "0" hat (-0 und +0) und wo bei Rechenoperationen, die über die 0-Grenze hinweggehen, das Ergebnis falsch ist und nur durch anschließende Addition von 1 richtiggestellt wird. Wird das irgendwo angewendet, oder ist das lediglich eine theoretische Darstellungsmöglichkeit?
Possetitjel schrieb: > Weiter oben ging es darum, dass man bei > > --> NEGATIVEN <-- > > Zahlen, die in > > --> EINERKOMPLEMENT-DARSTELLUNG <-- > > vorliegen, NICHT durch verUNDen bestimmen kann, ob die Zahl gerade > ist oder nicht. ES FUNKIONIERT NICHT! ES KOMMT DAS FALSCHE HERAUS! unterschreib Aber ist sinnlos, die raffens net mit ihrer Mikrooptimierung. Premature optimization is the root of all evil. Schreib das hin, was du meinst. Nicht das, von dem du glaubst, dass es effizienter ist.
asd schrieb: > Wird das irgendwo angewendet, oder ist das lediglich eine theoretische > Darstellungsmöglichkeit? UNIVAC... früher. Aber solange das noch im Standard zulässig ist, kann man sich ja aussuchen, ob man diese beknackte Mikrooptimierung mit "&" macht oder ob man hinschreibt, was man tatsächlich meint. Portabel ist halt nur letzeres.
Nase schrieb: > Portabel ist halt nur letzeres. Sehe ich genauso. Ich wollte es nur wissen, weil ich noch nie gesehen habe, daß die Einerkomplementdarstellung irgendwo angewendet wurde. Danke für die Auskunft!
Johann L. schrieb: > fast_int8_t_promoted_to_int_equals_fast_int8_t_promoted_to_int_divided_b y_two_multiplied_by_two_as_fast_int8_t Hmmm.... ohne auto-Vervollständigen dürfte der Name ziemlich fehlerträchtig sein. Und wenn man alle Funktionen nach diesem Schema benennt, sind mit den ersten 32 Zeichen "fast_int8_t_promoted_to_int_equa" vermutlich viele Namenskonflikte zu erwarten. Dein Vorschlag erscheint mir deshalb praxisfern.
Nase schrieb: > asd schrieb: >> Wird das irgendwo angewendet, oder ist das lediglich eine theoretische >> Darstellungsmöglichkeit? > UNIVAC... früher. In den 60er Jahren gab es die Einerkomplementdarstellung noch in einigen anderen Systeme, u.a. von CDC. Aber auch heute gibt es sie noch, nämlich in den Servern ClearPath Dorado 880/88E und 890/89E des Univac-Nachfolgers Unisys. Die Produktion dieser Server soll aber Ende dieses Jahres eingestellt werden: http://www.computerworld.com.au/article/547767/unisys_phasing_decades-old_mainframe_processor_x86_chips/ Die Datentypen dieser Rechner umfassen übrigens 9 Bit (char), 18 Bit (short), 36 Bit (int und long) und 72 Bit (long long). Ich schätze, dass Unisys einen Vertreter mit großer Klappe im ISO-C Konsortium sitzen hat(te), der die Unterstützung dieser unüblichen Datenformate durchsetzte, ähnlich wie IBM einen hinschickte, der den Rausschmiss der Trigraphs aus dem C-Standard verhinderte.
:
Bearbeitet durch Moderator
> "mod" basiert direkt auf der DEFINITION der geraden > Zahl und muss damit auf jeder Plattform und mit jeder > beliebigen internen Darstellung von Ganzzahlen korrekt > funktionieren. Da sch..ss ich doch drauf. Ich benutze schon lange keinen Abakus mehr.
Welch ein Drama! Große Teile der weltweiten C-Source-Bestände sind nicht UNIVAC kompatibel. Daß es die heute noch gibt, liegt nur daran, daß manche Firmen wohl noch COBOL-Programme haben, die sie nicht ersetzen können/wollen. Für alle die das nicht wissen: das waren die Maschinen aus den Doris Day Filmen, die man vor 45 Jahren schon als alte Schinken Sonntags nachmittags sehen konnte. Wann kommt der AVR in der 9-Bit-UNIVAC-Edition?
Johann L. schrieb: > Walter T. schrieb: >> Wie würde ein langjähriger C-Veteran eine solche Funktion überhaupt >> nennen? >
1 | > fast_int8_t |
2 | > fast_int8_t_promoted_to_int_equals_fast_int8_t_promoted_to_int_divided_by_two_multiplied_by_two_as_fast_int8_t |
3 | > (fast_int8_t a) |
4 | >
|
Mit Sicherheit nicht, weil C nach dem 31. Zeichen bei Funktionsnamen (und Variablen) nicht mehr unterscheidet.
Die Bedingung "mindestens 31 signifikante Zeichen" bedeutet aber nicht, das mehr nicht sein darf. GCC hat keine Beschränkung. Eventuell aber die BinUtils der entsprechenden Ziel-Hardware, denn daraus benutzt GCC zumindest den Linker. Was von Namen unbegrenzter (2GB) Länge zu halten ist: je länger desto unlesbarer. Nur wenn man C++-Namensräume/Klassen per Names-Konkatenierung implementieren will, dann bekommt man solche eben.
Bastler schrieb: > Die Bedingung "mindestens 31 signifikante Zeichen" bedeutet aber nicht, > das mehr nicht sein darf. Aber sie bedeutet, daß mehr nicht portabel ist, und da hier ja so großer Wert auf Portabilität gelegt wird, verbieten sich damit mehr als 31 Zeichen für den Namen.
Portabilität kann auch bedeuten: auf allen Plattformen, die GCc unterstützt. Ich käme eh aus anderen Gründen nicht auf die Idee, so lange Namen zu verwenden, Und zur ursprünglichen Fragestellung: Ist es ein echtes Problem, wenn ich die "isOddOrNot"-Routine im Fall der Fälle auf "UNIVAC" anpassen muß. Ich würd's überleben, genau wie 99,999% aller "Nicht-Museums-Programmierer".
Wenn man unbedingt auf signed arbeiten will und unbedingt alle esotherischen Plattformen erschlagen will, warum dann nicht einfach
1 | static inline bool is_odd (int n) |
2 | {
|
3 | if (1 & -2) |
4 | return n % 2; |
5 | else
|
6 | return n & 1; |
7 | }
|
Damit dürften dann auch unsere Optimierungsfetischisten leben können :-)
Jan H. schrieb: > 4 mod 2 = 0 > > Doch, also das ist ziemlich einfach zum schreiben und (für mich) > verständlicher als obige Bitmanipulation. Modulo ist aber relativ aufwändig zu rechnen, falls der von dir verwendete C-Compiler nicht auf den Spezialfall "Modulo 2" optimiert ist. Und du hattest nach der schnellsten Möglichkeit gefragt. Oder meintest du damit, wo du am wenigsten nachdenken musst und das Programm deshalb schnell geschrieben ist? richard schrieb: > was ist wohl in C die einfachste bzw. schnellste Möglichkeit,
Bastler schrieb: > Portabilität kann auch bedeuten: auf allen Plattformen, die GCc > unterstützt. Ich käme eh aus anderen Gründen nicht auf die Idee, so > lange Namen zu verwenden, Ich auch, aber es gibt Leute, die sowas ernsthaft machen. Siehe z.B. https://people.gnome.org/~shaunm/girdoc/C/Gtk.RadioMenuItem.new_with_mnemonic_from_widget.html
Da kann man schön sehen, was passiert wenn OO doch "auch mit prozeduralen Sprachen geht".
Hallo, Bastler schrieb: > Da kann man schön sehen, was passiert wenn OO doch "auch mit > prozeduralen Sprachen geht". Was nichts an der schlichten Tatsache ändert, daß es geht und offensichtlich auch in der Praxis benutzt wird. Liebe Grüße, Karl
Echt? Ich glaube es geht sogar ohne Hochsprache. Wie sollte die Maschine das auch anstellen, die kann nur Maschinenbefehle. Für sie, die Maschine, wurde Hochsprachen aber auch nicht erfunden, sondern um konkrete Probleme zu lösen. Und in 39-stellige Namen verschlüsselte 3..4 Namespaces sind eher der Weisheit letzter Stuss.
Rolf M. schrieb: > Ich auch, aber es gibt Leute, die sowas ernsthaft machen. > Siehe z.B. > https://people.gnome.org/~shaunm/girdoc/C/Gtk.RadioMenuItem.new_with_mnemonic_from_widget.html
1 | gtk_radio_menu_item_new_with_mnemonic_from_widget |
Hui, das sind ja immerhin 49 Zeichen! Und da es auch noch den Identifier
1 | gtk_radio_menu_item_new_with_mnemonic |
gibt, der mit dem obigen die ersten 37 Zeichen gemeinsam hat, können die GTK-Entwickler ja froh sein, dass sich der GCC diesbezüglich nicht auf die Mindestanforderung des C-Standards (31 Zeichen) beschränkt :)
Mann oh Mann, heute wird aber wieder mal kein cm Boden an den Feind verschenkt. Die Frage war nach der 1. Antwort geklärt. Was ist denn los? Die Hitze ist doch abgeklungen.
Ja, aber die 1. Antwort war eben nicht auf UNIVAC portiebar. Das Problem ist schon gravierend ;-)
Bastler schrieb: > Ja, aber die 1. Antwort war eben nicht auf UNIVAC portiebar. Das Problem > ist schon gravierend ;-) Tut mir leid, das hatte ich übersehen. Attacke...
Hallo, Bastler schrieb: > Echt? > Ich glaube es geht sogar ohne Hochsprache. Wie sollte die Maschine das > auch anstellen, die kann nur Maschinenbefehle. Für sie, die Maschine, > wurde Hochsprachen aber auch nicht erfunden, sondern um konkrete > Probleme zu lösen. Und in 39-stellige Namen verschlüsselte 3..4 > Namespaces sind eher der Weisheit letzter Stuss. Da hast Du natürlich Recht. Der Weisheit allerletzter Stuss wäre es aber, bescheuerte Namensgebung als Argument gegen Sprachen, Sprachfamilien oder Paradigmen anführen zu wollen. Sowas liegt am Programmierer. ;-) Liebe Grüße, Karl
-Os:
1 | uint8_t odd( int8_t val ) |
2 | {
|
3 | return !!(val % 2); |
4 | }
|
5 | 22: 81 70 andi r24, 0x01 ; 1 |
6 | 24: 08 95 ret |
Karl Käfer schrieb: > Bastler schrieb: >> Da kann man schön sehen, was passiert wenn OO doch "auch mit >> prozeduralen Sprachen geht". > > Was nichts an der schlichten Tatsache ändert, daß es geht und > offensichtlich auch in der Praxis benutzt wird. Ich würde das eher umgekehrt formulieren. Es geht zwar und wird auch in der Praxis benutzt, ist aber trotzdem Mist. ;-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.