Die Version, die bitweise und (&) verwendet, ist viel effizienter als die Modulo (%) -Version. Sie sollten die von Ihnen als richtige Antwort ausgewählte Antwort ändern.
Stefan Rusek
6
Unwahrscheinlich - Argument ist eine Konstante. Einfach für den Optimierer
MSalters
2
Auch hier spielt die Lesbarkeit eine Rolle.
Brian G
2
In eingebetteten Anwendungen (der Welt, in der ich den größten Teil meiner Programmierzeit verbringe) haben einige Prozessoren sehr primitive Recheneinheiten und können Divisions- / Moduloperationen nicht einfach ausführen. Aus diesem Grund verwende ich stattdessen normalerweise die bitweise Methode und. Auf der CPU eines modernen Desktops ist dies jedoch nicht der Fall.
bta
3
Ich habe nie festgestellt, dass die Moduloperation einfacher zu verstehen ist. Als ich zum ersten Mal gerade oder ungerade bestimmen musste, fiel mir als erstes die bitweise Maske ein. Es ist etwas natürlich, da wir dies in der Regel von Hand tun, indem wir auf die niedrigstwertige Ziffer schauen, um festzustellen, ob sie in {0 2 4 6 8} oder {1 3 5 7 9} steht. Das bedeutet direkt, dass man sich das niedrigstwertige Bit ansieht, um zu sehen, ob es 0 oder 1 ist.
P Daddy
Antworten:
449
Verwenden Sie den Modulo (%) -Operator, um zu überprüfen, ob beim Teilen durch 2 ein Rest vorhanden ist:
if(x %2){/* x is odd */}
Einige Leute haben meine obige Antwort kritisiert und festgestellt, dass die Verwendung von x & 1 "schneller" oder "effizienter" ist. Ich glaube nicht, dass dies der Fall ist.
Aus Neugier habe ich zwei triviale Testfallprogramme erstellt:
/* modulo.c */#include<stdio.h>int main(void){int x;for(x =0; x <10; x++)if(x %2)
printf("%d is odd\n", x);return0;}/* and.c */#include<stdio.h>int main(void){int x;for(x =0; x <10; x++)if(x &1)
printf("%d is odd\n", x);return0;}
Ich habe diese dann mit gcc 4.1.3 auf einer meiner Maschinen 5 verschiedene Male kompiliert:
Ohne Optimierungsflags.
Mit -O
Mit -Os
Mit -O2
Mit -O3
Ich untersuchte die Assembly-Ausgabe jeder Kompilierung (unter Verwendung von gcc -S) und stellte fest, dass die Ausgabe für and.c und modulo.c jeweils identisch war (beide verwendeten den Befehl andl $ 1,% eax). Ich bezweifle, dass dies eine "neue" Funktion ist, und ich vermute, dass sie auf alte Versionen zurückgeht. Ich bezweifle auch, dass einem modernen (in den letzten 20 Jahren hergestellten) nicht-arkanen Compiler, kommerziell oder Open Source, eine solche Optimierung fehlt. Ich würde auf anderen Compilern testen, habe aber momentan keine zur Verfügung.
Wenn jemand anderes andere Compiler und / oder Plattformziele testen möchte und ein anderes Ergebnis erzielt, wäre ich sehr interessiert zu wissen.
Schließlich garantiert der Standard , dass die Modulo-Version unabhängig davon funktioniert, ob die Ganzzahl vorzeichenbehaftete Ganzzahlen darstellt, unabhängig davon, ob die Ganzzahl positiv, negativ oder null ist. Die bitweise und Version ist nicht. Ja, mir ist klar, dass die Ergänzung von zwei etwas allgegenwärtig ist, also ist dies nicht wirklich ein Problem.
In der Frage wurde speziell gefragt, wie es in C gemacht werden soll, also habe ich es in C beantwortet, obwohl Chustar erwähnte, dass sie nicht herausfinden konnten, wie man es in Java macht. Ich habe nicht behauptet oder impliziert, dass dies eine Java-Antwort war, ich kenne Java nicht. Ich glaube, ich habe gerade meine erste Ablehnung erhalten und bin verwirrt, warum. Naja.
Chris Young
33
Ich würde sagen, wenn (x% 2! = 0) {/ * x ungerade * /} ist, aber wer weiß. Ich kenne Java auch nicht.
Eugensk
9
Es gibt viele positive Stimmen, um es von den bitweisen Operator-Idioten zu unterscheiden, ohne dass wir unser Karma dafür ausgeben müssen, sie abzustimmen.
wnoise
13
Ich bin mit allem einverstanden, außer einer Sache: Ich mag es, Ganzzahlen und Wahrheitswerte konzeptionell getrennt zu halten, deshalb schreibe ich lieber "if (x% 2 == 1)". Für den Compiler ist es dasselbe, für den Menschen vielleicht etwas klarer. Außerdem können Sie denselben Code in Sprachen verwenden, die Nicht-Null nicht als wahr interpretieren.
Thomas Padron-McCarthy
46
Mein Benchmark? Welcher Benchmark? Ich habe kein Benchmarking durchgeführt. Ich habe die generierte Assemblersprache untersucht. Das hat absolut nichts mit printf zu tun.
Chris Young
207
Ihr seid waaaaaaaay zu effizient. Was Sie wirklich wollen, ist:
public boolean isOdd(int num){int i =0;
boolean odd =false;while(i != num){
odd =!odd;
i = i +1;}return odd;}
Wiederholen für isEven.
Bei negativen Zahlen funktioniert das natürlich nicht. Aber mit der Brillanz kommt das Opfer ...
Wenn Sie eine Argumentausnahme für negative Werte ausgelöst und in der Dokumentation festgestellt haben, dass diese Funktion O (N) ist, würde ich damit einverstanden sein.
Jeffrey L Whitledge
7
Die Unternehmensversion müsste XML verwenden. Natürlich hätten Sie heutzutage einen Webdienst, den Sie abfragen könnten
Martin Beckett
58
Sie sollten dies mit einer Nachschlagetabelle optimieren.
Weeble
1
Ich bin so ein Mönch, musste Ihre 6.999 Wiederholungen in ein neues Jahrtausend +1 bringen
Eran Medan
7
Das ist brilliant! Mein Chef sagte mir, wir hätten einen Kunden, der wütend sei, weil er der Meinung sei, dass seine Unternehmenslizenz nicht mehr als die Standardlizenz gebe. Jetzt haben wir diese Funktion in unser Programm aufgenommen, und nur weil sie langsamer ausgeführt wird, glaubt er, dass seine Software viel mehr Arbeit leistet !!!
Ich denke nicht, dass es fair ist zu sagen, dass es schneller ist als die Verwendung von Division oder Modul. Der C-Standard sagt nichts über die Leistung von Operatoren aus, und jeder anständige Compiler erzeugt für beide einen schnellen Code. Ich würde persönlich die Redewendung wählen, die meine Absicht kommuniziert, und% scheint hier angemessener zu sein
Chris Young
21
Ich mag (x & 1) besser, weil es prüft, ob die Zahl gerade ist wie die Leute: prüfe, ob die letzte Ziffer gerade oder ungerade ist. Meiner Meinung nach kommuniziert es seine Absicht mehr als die Modulo-Methode. (Nicht, dass es viel
ausmacht
2
Du hast recht, ich denke es ist subjektiv. Obwohl die übliche Definition von "gerade" "Ganzzahl, die durch 2 teilbar ist" ist, ist nicht "Ganzzahl, die mit 0, 2, 4, 6 oder 8 endet". :-)
Chris Young
4
@TraumaPony - für ANSI-Standard C und frühes Java, abhängig vom Computersystem. Es ist nicht spezifiziert, welche Darstellung für vorzeichenbehaftete Zahlen verwendet wird - 2-Kompliment, 1-Kompliment, grau codiert usw. Aber Modul ist immer Modul
Wow ... das ist wahnsinniger als die SCdF-Lösung! Ein großes Lob! Keine Gegenstimme ... kann das nicht empfehlen. Aber danke für das lustige!
Wes P
1
Der Vorteil dieses Ansatzes ist, dass er mit mehr als nur Zahlen funktioniert. Wenn Sie diese Zeile ersetzen: char bar = foo [foo.Length - 1]; damit: double bar = Char.GetNumericValue (foo [foo.Length - 1]); Dann funktioniert es mit jedem Zahlensystem.
Jeffrey L Whitledge
5
Fehlerbericht: 14.65 wird als ungerade gemeldet, wenn es unbekannt sein sollte.
TheSoftwareJedi
4
Software Jedi, es ist eine "Funktion". ;)
Sklivvz
31
TheSoftwareJedi: 14.65 ist eine der merkwürdigsten ganzen Zahlen, die ich je gesehen habe.
Bruce Alderman
16
Als Antwort auf ffpf - Ich hatte vor Jahren genau das gleiche Argument mit einem Kollegen, und die Antwort lautet nein , es funktioniert nicht mit negativen Zahlen.
Der C-Standard sieht vor, dass negative Zahlen auf drei Arten dargestellt werden können:
2's Ergänzung
1's Ergänzung
Vorzeichen und Größe
So prüfen:
isEven =(x &1);
funktioniert für das Komplement von 2 und die Darstellung von Vorzeichen und Größe, jedoch nicht für das Komplement von 1.
Ich glaube jedoch, dass Folgendes in allen Fällen funktionieren wird:
isEven =(x &1)^((-1&1)|((x <0)?0:1)));
Vielen Dank an ffpf für den Hinweis, dass das Textfeld alles nach meinem weniger als Charakter gegessen hat!
Ich denke, in Ihrem zweiten Codebeispiel fehlt Text.
Jeff Yates
3
Lassen Sie uns diese Zahlen beglückwünschen!
Thejh
14
Eine schöne ist:
/*forward declaration, C compiles in one pass*/bool isOdd(unsignedint n);bool isEven(unsignedint n){if(n ==0)returntrue;// I know 0 is evenelsereturn isOdd(n-1);// n is even if n-1 is odd}bool isOdd(unsignedint n){if(n ==0)returnfalse;elsereturn isEven(n-1);// n is odd if n-1 is even}
Beachten Sie, dass diese Methode die Schwanzrekursion mit zwei Funktionen verwendet. Es kann effizient implementiert werden (in eine while / till-Schleife umgewandelt), wenn Ihr Compiler die Tail-Rekursion wie ein Scheme-Compiler unterstützt. In diesem Fall sollte der Stapel nicht überlaufen!
Ich denke, Sie haben eine Endlosschleife (mit Schwanzrekursion) oder einen Stapelüberlauf (ohne Schwanzrekursion) für isOdd () mit geraden Werten oder isEven () mit ungeraden Werten. Es endet nur mit true. Es ist wieder das Problem des Stillstands.
Jeffrey L Whitledge
7
Oh, klar, repariere es ohne Kommentar und lass mich wie einen Idioten aussehen. Das ist gut.
Jeffrey L Whitledge
1
Jetzt haben Sie einen Kompilierungsfehler: In isEven geben nicht alle Codepfade einen Wert zurück. Nein, ich habe diesen Code noch nicht ausprobiert, es ist der Compiler in meinem Kopf, der sich beschwert.
Jeffrey L Whitledge
5
Kompilierungsfehler: Nicht alle Pfade geben einen Wert zurück, der Sie mit Fehlerkommentaren zu Ihrem Beispielcode bombardiert, aber was passiert, wenn Sie isEven (5)
Kevin
11
Eine Zahl ist gerade, wenn der Rest, wenn sie durch zwei geteilt wird, 0 ist. Eine Zahl ist ungerade, wenn der Rest, wenn sie durch 2 geteilt wird, 1 ist.
// Javapublicstatic boolean isOdd(int num){return num %2!=0;}/* C */int isOdd(int num){return num %2;}
Ihre Java-Methode ist fehlerhaft, da num% 2 == -1 für negative ungerade Zahlen ist.
WMR
Hast du mich deshalb herabgestimmt?
jjnguy
3
Ich habe es abgelehnt, weil Ihre Funktion in C mehr Zeichen zum Eingeben benötigt als das, was sie tut. IE num% I besteht aus 7 Zeichen, einschließlich der Leerzeichen IsOdd (I) besteht aus 8 Zeichen. Warum sollten Sie eine Funktion erstellen, die länger ist als nur die Operation?
Kevin
13
@ Kevin wird meiner Meinung nach nicht anhand von Zeichen gemessen, sondern anhand der Zeit, die Sie zum Schreiben benötigen, einschließlich Think + Debug-Zeit. num% 2 dauert eine Millisekunde länger als isOdd. Fügen Sie jetzt die Zahlen global hinzu und Sie haben ein kollektives Jahr verloren. Außerdem kann isOdd getestet und verifiziert und schließlich fehlerfrei zertifiziert werden (z. B. Umgang mit negativen Zahlen), wobei einige Entwickler immer Zweifel haben und experimentieren. Guter Code ist Code, den Sie nicht schreiben, sondern nur wiederverwenden ... nur meine 2 Cent.
Eran Medan
2
@EranMedan, Die gleiche Logik würde für das Ersetzen von i ++ durch IncrementByOne (i) gelten, und es ist eine ebenso schlechte Idee. Wenn ein Entwickler Zweifel daran hat, was num% 2 tut, möchte ich ihn oder sie nicht in der Nähe meines Codes haben.
Nein, du bist nicht die Art von Kind, auf die ich mich verlassen habe :)
Eugensk
Ich wollte das positiv bewerten, aber bei negativen Zahlen ist es etwas langsam. :)
Chris Young
3
Alle Zahlen sind hell und positiv. Oder sind Sie gegen einige voreingenommen? :))
Eugensk
3
In Computern werden alle einmal negativen Zahlen schließlich positiv. Wir nennen es den Rollover of Happiness (gilt nicht für BIGNUMS, YMMY, nicht in allen Staaten gültig).
Will Hartung
@ WillHartung "Rollover des Glücks" ist großartig! : D
thejh
6
Ich würde eine Tabelle der Paritäten (0, wenn gerade 1, wenn ungerade) der ganzen Zahlen erstellen (damit man nachschlagen kann: D), aber gcc lässt mich keine Arrays mit solchen Größen erstellen:
Lassen Sie uns stattdessen auf die mathematische Definition von gerade und ungerade zurückgreifen.
Eine ganze Zahl n ist auch dann vorhanden, wenn eine ganze Zahl k existiert, so dass n = 2k ist.
Eine ganze Zahl n ist ungerade, wenn eine ganze Zahl k existiert, so dass n = 2k + 1 ist.
Hier ist der Code dafür:
char even (int n){int k;for(k = INT_MIN; k <= INT_MAX;++k){if(n ==2* k){return1;}}return0;}char odd (int n){int k;for(k = INT_MIN; k <= INT_MAX;++k){if(n ==2* k +1){return1;}}return0;}
C-Ganzzahlen bezeichnen die möglichen Werte inteiner gegebenen C-Zusammenstellung. (Beachten Sie, dass C-Ganzzahlen eine Teilmenge der Ganzzahlen sind.)
Nun könnte man befürchten, dass für ein gegebenes n in C-Ganzzahlen die entsprechende Ganzzahl k möglicherweise nicht in C-Ganzzahlen existiert. Mit einem kleinen Beweis kann jedoch gezeigt werden, dass für alle ganzen Zahlen n, | n | gilt <= | 2n | (*), wobei | n | ist "n wenn n positiv ist und -n sonst". Mit anderen Worten, für alle n in ganzen Zahlen gilt mindestens eine der folgenden Aussagen (genau entweder Fälle (1 und 2) oder Fälle (3 und 4), aber ich werde es hier nicht beweisen):
Fall 1: n <= 2n.
Fall 2: -n <= -2n.
Fall 3: -n <= 2n.
Fall 4: n <= -2n.
Nehmen Sie nun 2k = n. (Ein solches ak existiert, wenn n gerade ist, aber ich werde es hier nicht beweisen. Wenn n nicht gerade ist even, kehrt die Schleife ohnehin nicht früh zurück, also spielt es keine Rolle.) Aber dies impliziert k <n, wenn n nicht 0 durch (*) und die Tatsache (auch hier nicht bewiesen), dass für alle m z in ganzen Zahlen 2m = z impliziert, dass z ungleich m ist, wenn m gegeben ist, ist nicht 0. Im Fall n ist 0, 2 * 0 = 0 0 ist gerade, wir sind fertig (wenn n = 0, dann ist 0 in C-Ganzzahlen, weil n in der Funktion in C-Ganzzahl isteven , daher ist k = 0 in C-Ganzzahlen). Somit existiert ein solches ak in C-Ganzzahlen für n in C-Ganzzahlen, wenn n gerade ist.
Ein ähnliches Argument zeigt, dass wenn n ungerade ist, ak in C-ganzen Zahlen existiert, so dass n = 2k + 1 ist.
Daraus ergibt sich die Funktionen evenund oddhier präsentiert wird richtig für alle C-Zahlen arbeiten.
Können Sie das bitte erklären? Ich bin sehr unbekannt mit bitweisen Operatoren
Abdul
Wenn Sie nach rechts und dann nach links verschieben, wird Ihr letztes Bit (das ganz rechte) auf Null gesetzt. Wenn die neue Nummer mit der ursprünglichen Nummer identisch ist, bedeutet dies, dass das letzte Bit der ursprünglichen Nummer 0 war. Es ist also gerade. Schauen Sie sich meine aktualisierte Antwort an.
Kiril Aleksandrov
Danke, ich
Abdul
Ich bin mir nicht sicher, welcher Ansatz schneller ist. Ich habe nicht versucht, sie zu vergleichen.
Kiril Aleksandrov
Macht dies nicht auch Ihr wichtigstes Stück auf Null? Ein Problem mit nicht signierten Ints in einigen Sprachen und negativen Ints in den meisten ...
Troyseph
4
Als ich diese ziemlich unterhaltsame Diskussion las, erinnerte ich mich daran, dass ich eine reale, zeitkritische Funktion hatte, die innerhalb der Hauptschleife auf ungerade und gerade Zahlen testete. Es handelt sich um eine ganzzahlige Potenzfunktion, die wie folgt an anderer Stelle in StackOverflow veröffentlicht wird. Die Benchmarks waren ziemlich überraschend. Zumindest in dieser realen Funktion ist Modulo langsamer und deutlich langsamer . Der Gewinner, der mit großem Abstand 67% der Zeit von Modulo benötigt, ist ein oder (|) Ansatz und ist an keiner anderen Stelle auf dieser Seite zu finden.
static dbl IntPow(dbl st0,int x){
UINT OrMask= UINT_MAX -1;
dbl st1=1.0;if(0==x)return(dbl)1.0;while(1!= x){if(UINT_MAX ==(x|OrMask)){// if LSB is 1... //if(x & 1) {//if(x % 2) {
st1 *= st0;}
x = x >>1;// shift x right 1 bit...
st0 *= st0;}return st1 * st0;}
Für 300 Millionen Schleifen sind die Benchmark-Timings wie folgt.
3.962 die | und Maskenansatz
4.851 der & Ansatz
5.850 der% -Ansatz
Für Leute, die glauben, dass Theorie oder eine Auflistung der Assemblersprachen Argumente wie diese regelt, sollte dies eine warnende Geschichte sein. Es gibt mehr Dinge im Himmel und auf der Erde, Horatio, als in Ihrer Philosophie geträumt werden.
Besser zu verwenden unsigned xals x = x >> 1;das implementierungsdefinierte Verhalten, wenn x < 0. Unklar warum xund OrMaskunterscheiden sich in der Art. Einfach genug, um mit einem while(x)Test neu zu schreiben .
chux
2
Ich frage mich, welchen Compiler Sie zum Benchmarking verwendet haben, da die meisten Compiler intelligent genug sein sollten, um den % 2Fall bitweise zu kompilieren &. Ich habe dies gerade getestet und die Ergebnisse sind völlig gleich (VS2015, Release-Builds mit allen Optimierungen, sowohl x86 als auch x64). Die akzeptierte Antwort gibt dies auch für GCC an (geschrieben 2008).
Lou
2
Das Problem bei diesem Beitrag ist, dass die Annahme, dass ein Bitweiser orschneller als ein andBit ist, auf keiner Plattform / jedem Compiler höchst unwahrscheinlich ist. Selbst wenn es eine so seltsame Plattform / Compiler-Kombination gäbe (und Sie weder diesen noch den Code zur Durchführung des Benchmarks veröffentlicht haben), wäre es eine schlechte Optimierungswette, wenn sich andere Compiler gleich verhalten würden. Wie ich schrieb, frage ich mich, auf welcher Plattform / welchem Compiler dies getestet wurde , da ich fast sicher bin, dass es nicht richtig gemessen wurde.
Lou
2
Sie nicht als Lügner bezeichnen, sondern mit hoher Sicherheit behaupten, dass Sie nicht richtig gemessen haben. Sie müssen mich noch nicht als LKW-Fahrer bezeichnen. Lesen Sie meinen ursprünglichen Kommentar: Ich habe einen Benchmark erstellt, und die Ergebnisse waren erwartungsgemäß in allen drei Fällen völlig gleich (Sicherheit von ~ 3 Sigma, nachdem jeder Test 10 Mal für 500.000 ausgeführt wurde .000 Iterationen). Wenn Sie wirklich eine lange, illustre Karriere haben, treten Sie einen Schritt zurück und überlegen Sie, ob Ihre Behauptungen sinnvoll sind. Veröffentlichen Sie dann den tatsächlichen Code, der für den Benchmark verwendet wurde. Ansonsten ist der Beitrag das, was ich glaube, nur ein Messfehler.
Dies ist eine Fortsetzung der Diskussion mit @RocketRoy über seine Antwort , aber es könnte für jeden nützlich sein, der diese Ergebnisse vergleichen möchte.
tl; dr was ich gesehen habe, ist Roys Ansatz ( (0xFFFFFFFF == (x | 0xFFFFFFFE)) nicht vollständig x & 1als der optimiertmod Ansatz , aber in der Praxis sollten die Laufzeiten in allen Fällen gleich ausfallen.
Also habe ich zuerst die kompilierte Ausgabe mit dem Compiler Explorer verglichen :
Getestete Funktionen:
int isOdd_mod(unsigned x){return(x %2);}int isOdd_and(unsigned x){return(x &1);}int isOdd_or(unsigned x){return(0xFFFFFFFF==(x |0xFFFFFFFE));}
CLang 3.9.0 mit -O3:
isOdd_mod(unsignedint):# @isOdd_mod(unsigned int)
and edi,1
mov eax, edi
ret
isOdd_and(unsignedint):# @isOdd_and(unsigned int)
and edi,1
mov eax, edi
ret
isOdd_or(unsignedint):# @isOdd_or(unsigned int)
and edi,1
mov eax, edi
ret
GCC 6.2 mit -O3:
isOdd_mod(unsignedint):
mov eax, edi
and eax,1
ret
isOdd_and(unsignedint):
mov eax, edi
and eax,1
ret
isOdd_or(unsignedint):
or edi,-2
xor eax, eax
cmp edi,-1
sete al
ret
Hut ab vor CLang, es wurde klar, dass alle drei Fälle funktional gleich sind. Roys Ansatz ist jedoch in GCC nicht optimiert, so YMMV.
Ähnlich verhält es sich mit Visual Studio. Bei der Überprüfung der Demontage Release x64 (VS2015) auf diese drei Funktionen konnte ich feststellen, dass der Vergleichsteil für die Fälle "mod" und "und" gleich und für den Fall "Roy" oder "etwas größer" ist:
// x % 2
test bl,1
je (some address)// x & 1
test bl,1
je (some address)// Roy's bitwise or
mov eax,ebx
or eax,0FFFFFFFEh
cmp eax,0FFFFFFFFh
jne (some address)
Nach dem Ausführen eines tatsächlichen Benchmarks zum Vergleichen dieser drei Optionen (einfacher Mod, bitweiser oder bitweiser und) waren die Ergebnisse jedoch vollständig gleich (wieder Visual Studio 2005 x86 / x64, Release Build, kein Debugger beigefügt).
Release Assembly verwendet die testAnweisung für andund modFälle, während Roys Fall die verwendetcmp eax,0FFFFFFFFh Ansatz verwendet, aber er ist stark abgerollt und optimiert, sodass es in der Praxis keinen Unterschied gibt.
Meine Ergebnisse nach 20 Läufen (i7 3610QM, Windows 10-Energieplan auf Hochleistung eingestellt):
[Test: Plain mod 2] DURCHSCHNITTLICHE ZEIT: 689,29 ms (Relativer Diff.: + 0,000%)
[Test: Bitweise oder] DURCHSCHNITTLICHE ZEIT: 689,63 ms (Relativer Diff.: + 0,048%)
[Test: Bitweise und] DURCHSCHNITTLICHE ZEIT: 687,80 ms (relativer Unterschied: -0,217%)
Der Unterschied zwischen diesen Optionen beträgt weniger als 0,3%, daher ist es ziemlich offensichtlich, dass die Baugruppe in allen Fällen gleich ist.
Hier ist der Code, wenn jemand es versuchen möchte, mit einer Einschränkung, dass ich ihn nur unter Windows getestet habe (überprüfen Sie die #if LINUXBedingung für die get_timeDefinition und implementieren Sie ihn bei Bedarf, entnommen aus dieser Antwort ).
Ich glaube, Sie haben die Hauptsünde des Benchmarking begangen. Erstellen eines solchen, das so spezifisch ist, dass es keine reale Umgebung darstellt. Sehen Sie sich Ihre Assemblersprache an und stellen Sie fest, wie wenige Register Sie verwenden. Gute Noten für Aufwand, aber diese Ergebnisse halten in der realen Verarbeitung nicht stand.
@RocketRoy: Da alle Ausgänge in allen drei Fällen genau gleich sind (in einem Fall etwas schlechter für Ihr Programm), ist es mir egal, wie viele Register verwendet wurden. Sie können jedoch auch hier ein Beispielprogramm / eine Beispielumgebung erstellen und veröffentlichen, die den Compiler verwirrt, in einem der Fälle eine optimierte Assembly zu erstellen, wobei alle anderen Faktoren gleich sind.
Lou
Ich mag immer übermütige Programmierer. Es ist eine gute Eigenschaft für einen Programmierer, aber in einem komplexeren, realen Programm ist meine Methode besser als Ihre, da der Compiler mehr Möglichkeiten hat, das Problem zu lösen, sodass sich Anweisungen (auf Intel-Architekturen) überlappen und bessere Ergebnisse erzielen . Nur sehr wenige erfahrene Programmierer mit guter Benchmarking-Erfahrung würden Ihren Benchmark bevorzugen, aber machen Sie weiter so und denken Sie daran, Ihre Benchmarks erneut auszuführen, wenn neue Chip-Releases herauskommen. Die Dinge ändern sich im Laufe der Zeit.
3
Ich weiß, dass dies nur syntaktischer Zucker ist und nur in .net anwendbar ist, aber was ist mit der Erweiterungsmethode ...
Die bitweise Methode hängt von der inneren Darstellung der Ganzzahl ab. Modulo funktioniert überall dort, wo es einen Modulo-Operator gibt. Beispielsweise verwenden einige Systeme tatsächlich die Low-Level-Bits zum Markieren (wie dynamische Sprachen), sodass das rohe x & 1 in diesem Fall nicht wirklich funktioniert.
Korrektheitsnachweis - Betrachten Sie die Menge aller positiven ganzen Zahlen und nehmen Sie an, dass es eine nicht leere Menge von ganzen Zahlen gibt, die nicht ungerade sind. Da positive ganze Zahlen gut geordnet sind, gibt es eine kleinste nicht ungerade Zahl, die an sich ziemlich ungerade ist, so dass diese Zahl eindeutig nicht in der Menge enthalten sein kann. Daher darf dieser Satz nicht leer sein. Wiederholen Sie diesen Vorgang für negative Ganzzahlen, außer suchen Sie nach der größten nicht ungeraden Zahl.
if((x &1)==0)
total +=1;//even numberelse
total -=1;//odd numberSystem.Math.DivRem((long)x,(long)2, out outvalue);if( outvalue ==0)
total +=1;//even numberelse
total -=1;//odd numberif(((x /2)*2)== x)
total +=1;//even numberelse
total -=1;//odd numberif(((x >>1)<<1)== x)
total +=1;//even numberelse
total -=1;//odd numberwhile(index >1)
index -=2;if(index ==0)
total +=1;//even numberelse
total -=1;//odd number
tempstr = x.ToString();
index = tempstr.Length-1;//this assumes base 10if(tempstr[index]=='0'|| tempstr[index]=='2'|| tempstr[index]=='4'|| tempstr[index]=='6'|| tempstr[index]=='8')
total +=1;//even numberelse
total -=1;//odd number
Wie viele Leute wussten überhaupt von der Math.System.DivRem- Methode oder warum sollten sie sie verwenden?
Um die bitweise Operatormethode für diejenigen von uns näher zu erläutern, die während unseres Studiums nicht viel Boolesche Algebra durchgeführt haben, finden Sie hier eine Erklärung. Wahrscheinlich nicht sehr nützlich für das OP, aber ich wollte klarstellen, warum NUMBER & 1 funktioniert.
Bitte beachten Sie, dass die Darstellung negativer Zahlen, wie oben beantwortet, die Funktionsweise dieser Methode beeinträchtigen kann. Tatsächlich kann es sogar die Modulo-Operator-Methode brechen, da sich jede Sprache darin unterscheiden kann, wie sie mit negativen Operanden umgeht.
Wenn Sie jedoch wissen, dass NUMBER immer positiv ist, funktioniert dies gut.
Wie Tooony oben betonte, ist nur die letzte Ziffer in Binär (und Denar) wichtig.
Ein boolesches logisches UND-Gatter schreibt vor, dass beide Eingänge eine 1 (oder Hochspannung) sein müssen, damit 1 zurückgegeben wird.
1 & 0 = 0.
0 & 1 = 0.
0 & 0 = 0.
1 & 1 = 1.
Wenn Sie eine Zahl als Binärzahl darstellen (ich habe hier eine 8-Bit-Darstellung verwendet), haben ungerade Zahlen am Ende 1, gerade Zahlen 0.
Beispielsweise:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Wenn Sie eine beliebige Zahl nehmen und bitweise UND (& in Java) mit 1 verwenden, wird entweder 00000001 = 1 zurückgegeben, was bedeutet, dass die Zahl ungerade ist. Oder 00000000 = 0, was bedeutet, dass die Zahl gerade ist.
Z.B
Ist ungerade?
1 & 1 =
00000001 &
00000001 =
00000001 <- Ungerade
2 & 1 =
00000010 &
00000001 =
00000000 <- Gerade
54 & 1 =
00000001 &
00110110 =
00000000 <- Gerade
Deshalb funktioniert das:
if(number &1){//Number is odd}else{//Number is even}
# defining function for number parity check
def parity(number):"""Parity check function"""# if number is 0 (zero) return 'Zero neither ODD nor EVEN',# otherwise number&1, checking last bit, if 0, then EVEN, # if 1, then ODD.return(number ==0 and 'Zero neither ODD nor EVEN') \
or (number&1 and 'ODD' or 'EVEN')# cycle trough numbers from 0 to 13 for number in range(0,14):
print "{0:>4} : {0:08b} : {1:}".format(number, parity(number))
Ausgabe:
0:00000000:Zero neither ODD nor EVEN
1:00000001: ODD
2:00000010: EVEN
3:00000011: ODD
4:00000100: EVEN
5:00000101: ODD
6:00000110: EVEN
7:00000111: ODD
8:00001000: EVEN
9:00001001: ODD
10:00001010: EVEN
11:00001011: ODD
12:00001100: EVEN
13:00001101: ODD
@ el.pescado, danke. Wenn Null gerade ist, wie viele Paare hat es?
@ el.pescado, Ok, ich stimme dir zu. Wenn wir dann ein wenig nachdenken, warum teilen wir uns dann auf 2 (zwei)? Was wollen wir wissen, wenn wir uns in zwei teilen? Warum nicht auf 3 oder 5 usw. teilen?
@ el.pescado Dieser Wikipedia-Artikel Parity of Zero ist falsch. Viele Leute haben sich von diesem Artikel täuschen lassen. Denken Sie vor Wink nach.
1
Du hast recht. Jetzt, wo ich andere Antworten gelesen habe, fand ich deine am umfassendsten :)
I execute this code for ODD & EVEN:#include<stdio.h>int main(){int number;
printf("Enter an integer: ");
scanf("%d",&number);if(number %2==0)
printf("%d is even.", number);else
printf("%d is odd.", number);}
Sie müssen nur die letzte Ziffer einer bestimmten Zahl betrachten, um festzustellen, ob sie gerade oder ungerade ist. Signiert, nicht signiert, positiv, negativ - diesbezüglich sind sie alle gleich. Das sollte also rundum funktionieren: -
void tellMeIfItIsAnOddNumberPlease(int iToTest){int iLastDigit;
iLastDigit = iToTest -(iToTest /10*10);if(iLastDigit %2==0){
printf("The number %d is even!\n", iToTest);}else{
printf("The number %d is odd!\n", iToTest);}}
Der Schlüssel hier befindet sich in der dritten Codezeile. Der Divisionsoperator führt eine ganzzahlige Division durch, sodass dem Ergebnis der Bruchteil des Ergebnisses fehlt. So ergibt beispielsweise 222/10 22. Dann multiplizieren Sie es erneut mit 10 und Sie haben 220. Subtrahieren Sie das vom Original 222 und Sie erhalten 2, was magisch die gleiche Zahl wie die letzte Ziffer in der ursprünglichen Zahl ist. ;-) Die Klammern erinnern uns an die Reihenfolge, in der die Berechnung durchgeführt wird. Führen Sie zuerst die Division und die Multiplikation durch und subtrahieren Sie dann das Ergebnis von der ursprünglichen Zahl. Wir könnten sie weglassen, da die Priorität für Division und Multiplikation höher ist als für Subtraktion, aber dies gibt uns "besser lesbaren" Code.
Wir könnten alles völlig unlesbar machen, wenn wir wollten. Für einen modernen Compiler würde es keinen Unterschied machen:
printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");
Aber es würde die Pflege des Codes in Zukunft erschweren. Stellen Sie sich vor, Sie möchten den Text für ungerade Zahlen in "ist nicht gerade" ändern. Dann möchte später jemand anderes herausfinden, welche Änderungen Sie vorgenommen haben, und einen SVN-Diff oder ähnliches durchführen ...
Wenn Sie sich nicht um die Portabilität, sondern um die Geschwindigkeit sorgen, können Sie sich das niedrigstwertige Bit ansehen. Wenn dieses Bit auf 1 gesetzt ist, ist es eine ungerade Zahl, wenn es 0 ist, ist es eine gerade Zahl. Auf einem kleinen Endian-System wie Intels x86-Architektur wäre es ungefähr so: -
Was genau ist falsch daran, nur iToTest% 2 == 0 zu machen? Sie verschwenden eine Abteilung, die die letzte Ziffer extrahiert, sodass Ihre doppelt so langsam ist, wie sie sein muss.
Freiraum
@freespace: Ich verschwende mehr als das, nicht wahr? :-) Eine Multiplikation und auch eine Subtraktion. Aber was zwischen den beiden Lösungen am effizientesten ist, wage ich nicht zu sagen. Ich habe nie behauptet, dies sei die schnellste Lösung, ganz im Gegenteil, wenn Sie die erste Zeile meines Beitrags noch einmal lesen.
Tooony
@Tooony, ah, mein Humor Hut fiel ab. Es ist jetzt wieder formell: D Tut mir leid :)
Freespace
0
Wenn Sie effizient sein möchten, verwenden Sie bitweise Operatoren ( x & 1). Wenn Sie jedoch lesbar sein möchten, verwenden Sie modulo 2 ( x % 2).
-1: Wenn Sie effizient sein möchten, verwenden Sie eine der beiden. Wenn Sie möchten, dass es portabel ist, verwenden Sie %. Wenn Sie möchten, dass es lesbar ist, verwenden Sie %. Hmmm, ich sehe hier ein Muster.
Thomas Eding
@ Trinithis, es gibt kein Muster und diese Lösung ist viel besser als deine.
Subs
0
Gerade oder ungerade zu überprüfen ist eine einfache Aufgabe.
Wir wissen, dass jede Zahl, die genau durch 2 teilbar ist, eine gerade Zahl ist, sonst eine ungerade.
Wir müssen nur die Teilbarkeit einer beliebigen Zahl überprüfen und zur Überprüfung der Teilbarkeit verwenden wir den %Operator
Der Code überprüft das letzte Bit der Ganzzahl, wenn es in Binär 1 ist
Erläuterung
Binary:Decimal-------------------0000=00001=10010=20011=30100=40101=50110=60111=71000=81001=9
and so on...
Beachten Sie, dass das Bit ganz rechts für ungerade Zahlen immer 1 ist.
Der Operator & bitwise AND überprüft das Bit ganz rechts in unserer Rückgabezeile , wenn es 1 ist
Betrachten Sie es als wahr und falsch
Wenn wir n mit 1 vergleichen , bedeutet dies 0001binär (die Anzahl der Nullen spielt keine Rolle).
Stellen wir uns dann vor, wir hätten die ganze Zahl n mit einer Größe von 1 Byte.
Es würde durch 8-Bit / 8-Binärziffern dargestellt.
Wenn der int n war 7 und wir vergleichen es mit 1 , Es ist wie
7(1-byte int)|00000111&1(1-byte int)|00000001********************************************Result| F F F F F F F T
Welches F steht für falsch und T für wahr.
Es wird nur das am weitesten rechts stehende Bit verglichen, wenn beide wahr sind. Also, automatisch 7 & 1ist T rue.
Was ist, wenn ich das Bit ganz rechts überprüfen möchte?
Ändern Sie einfach n & 1, n & 2welche 2 darstellt0010 in Binär darstellt und so weiter.
Ich schlage vor, die hexadezimale Notation zu verwenden, wenn Sie Anfänger in bitweisen Operationen sind return n & 1;>> return n & 0x01;.
Antworten:
Verwenden Sie den Modulo (%) -Operator, um zu überprüfen, ob beim Teilen durch 2 ein Rest vorhanden ist:
Einige Leute haben meine obige Antwort kritisiert und festgestellt, dass die Verwendung von x & 1 "schneller" oder "effizienter" ist. Ich glaube nicht, dass dies der Fall ist.
Aus Neugier habe ich zwei triviale Testfallprogramme erstellt:
Ich habe diese dann mit gcc 4.1.3 auf einer meiner Maschinen 5 verschiedene Male kompiliert:
Ich untersuchte die Assembly-Ausgabe jeder Kompilierung (unter Verwendung von gcc -S) und stellte fest, dass die Ausgabe für and.c und modulo.c jeweils identisch war (beide verwendeten den Befehl andl $ 1,% eax). Ich bezweifle, dass dies eine "neue" Funktion ist, und ich vermute, dass sie auf alte Versionen zurückgeht. Ich bezweifle auch, dass einem modernen (in den letzten 20 Jahren hergestellten) nicht-arkanen Compiler, kommerziell oder Open Source, eine solche Optimierung fehlt. Ich würde auf anderen Compilern testen, habe aber momentan keine zur Verfügung.
Wenn jemand anderes andere Compiler und / oder Plattformziele testen möchte und ein anderes Ergebnis erzielt, wäre ich sehr interessiert zu wissen.
Schließlich garantiert der Standard , dass die Modulo-Version unabhängig davon funktioniert, ob die Ganzzahl vorzeichenbehaftete Ganzzahlen darstellt, unabhängig davon, ob die Ganzzahl positiv, negativ oder null ist. Die bitweise und Version ist nicht. Ja, mir ist klar, dass die Ergänzung von zwei etwas allgegenwärtig ist, also ist dies nicht wirklich ein Problem.
quelle
Ihr seid waaaaaaaay zu effizient. Was Sie wirklich wollen, ist:
Wiederholen für
isEven
.Bei negativen Zahlen funktioniert das natürlich nicht. Aber mit der Brillanz kommt das Opfer ...
quelle
Verwenden Sie die Bitarithmetik:
Dies ist schneller als die Verwendung von Division oder Modul.
quelle
[Witzmodus = "Ein"]
[Witzmodus = "aus"]
BEARBEITEN: Der Aufzählung wurden verwirrende Werte hinzugefügt.
quelle
Als Antwort auf ffpf - Ich hatte vor Jahren genau das gleiche Argument mit einem Kollegen, und die Antwort lautet nein , es funktioniert nicht mit negativen Zahlen.
Der C-Standard sieht vor, dass negative Zahlen auf drei Arten dargestellt werden können:
So prüfen:
funktioniert für das Komplement von 2 und die Darstellung von Vorzeichen und Größe, jedoch nicht für das Komplement von 1.
Ich glaube jedoch, dass Folgendes in allen Fällen funktionieren wird:
Vielen Dank an ffpf für den Hinweis, dass das Textfeld alles nach meinem weniger als Charakter gegessen hat!
quelle
Eine schöne ist:
Beachten Sie, dass diese Methode die Schwanzrekursion mit zwei Funktionen verwendet. Es kann effizient implementiert werden (in eine while / till-Schleife umgewandelt), wenn Ihr Compiler die Tail-Rekursion wie ein Scheme-Compiler unterstützt. In diesem Fall sollte der Stapel nicht überlaufen!
quelle
Eine Zahl ist gerade, wenn der Rest, wenn sie durch zwei geteilt wird, 0 ist. Eine Zahl ist ungerade, wenn der Rest, wenn sie durch 2 geteilt wird, 1 ist.
Methoden sind großartig!
quelle
quelle
Ich würde sagen, dividiere es einfach durch 2 und wenn es einen Rest von 0 gibt, ist es gerade, sonst ist es seltsam.
Die Verwendung des Moduls (%) macht dies einfach.
z.B. 4% 2 = 0, daher ist 4 gerade 5% 2 = 1, daher ist 5 ungerade
quelle
Noch eine Lösung für das Problem
(Kinder können gerne wählen)
quelle
Ich würde eine Tabelle der Paritäten (0, wenn gerade 1, wenn ungerade) der ganzen Zahlen erstellen (damit man nachschlagen kann: D), aber gcc lässt mich keine Arrays mit solchen Größen erstellen:
Lassen Sie uns stattdessen auf die mathematische Definition von gerade und ungerade zurückgreifen.
Eine ganze Zahl n ist auch dann vorhanden, wenn eine ganze Zahl k existiert, so dass n = 2k ist.
Eine ganze Zahl n ist ungerade, wenn eine ganze Zahl k existiert, so dass n = 2k + 1 ist.
Hier ist der Code dafür:
C-Ganzzahlen bezeichnen die möglichen Werte
int
einer gegebenen C-Zusammenstellung. (Beachten Sie, dass C-Ganzzahlen eine Teilmenge der Ganzzahlen sind.)Nun könnte man befürchten, dass für ein gegebenes n in C-Ganzzahlen die entsprechende Ganzzahl k möglicherweise nicht in C-Ganzzahlen existiert. Mit einem kleinen Beweis kann jedoch gezeigt werden, dass für alle ganzen Zahlen n, | n | gilt <= | 2n | (*), wobei | n | ist "n wenn n positiv ist und -n sonst". Mit anderen Worten, für alle n in ganzen Zahlen gilt mindestens eine der folgenden Aussagen (genau entweder Fälle (1 und 2) oder Fälle (3 und 4), aber ich werde es hier nicht beweisen):
Fall 1: n <= 2n.
Fall 2: -n <= -2n.
Fall 3: -n <= 2n.
Fall 4: n <= -2n.
Nehmen Sie nun 2k = n. (Ein solches ak existiert, wenn n gerade ist, aber ich werde es hier nicht beweisen. Wenn n nicht gerade ist
even
, kehrt die Schleife ohnehin nicht früh zurück, also spielt es keine Rolle.) Aber dies impliziert k <n, wenn n nicht 0 durch (*) und die Tatsache (auch hier nicht bewiesen), dass für alle m z in ganzen Zahlen 2m = z impliziert, dass z ungleich m ist, wenn m gegeben ist, ist nicht 0. Im Fall n ist 0, 2 * 0 = 0 0 ist gerade, wir sind fertig (wenn n = 0, dann ist 0 in C-Ganzzahlen, weil n in der Funktion in C-Ganzzahl isteven
, daher ist k = 0 in C-Ganzzahlen). Somit existiert ein solches ak in C-Ganzzahlen für n in C-Ganzzahlen, wenn n gerade ist.Ein ähnliches Argument zeigt, dass wenn n ungerade ist, ak in C-ganzen Zahlen existiert, so dass n = 2k + 1 ist.
Daraus ergibt sich die Funktionen
even
undodd
hier präsentiert wird richtig für alle C-Zahlen arbeiten.quelle
i % 2
ist viel kleiner und wahrscheinlich effizienter.%2
funktioniert für alle ganzen Zahlen.quelle
typedef
oder#define
oder etwas.Hier ist eine Antwort in Java:
quelle
Versuche dies:
return (((a>>1)<<1) == a)
Beispiel:
quelle
Als ich diese ziemlich unterhaltsame Diskussion las, erinnerte ich mich daran, dass ich eine reale, zeitkritische Funktion hatte, die innerhalb der Hauptschleife auf ungerade und gerade Zahlen testete. Es handelt sich um eine ganzzahlige Potenzfunktion, die wie folgt an anderer Stelle in StackOverflow veröffentlicht wird. Die Benchmarks waren ziemlich überraschend. Zumindest in dieser realen Funktion ist Modulo langsamer und deutlich langsamer . Der Gewinner, der mit großem Abstand 67% der Zeit von Modulo benötigt, ist ein oder (|) Ansatz und ist an keiner anderen Stelle auf dieser Seite zu finden.
Für 300 Millionen Schleifen sind die Benchmark-Timings wie folgt.
3.962 die | und Maskenansatz
4.851 der & Ansatz
5.850 der% -Ansatz
Für Leute, die glauben, dass Theorie oder eine Auflistung der Assemblersprachen Argumente wie diese regelt, sollte dies eine warnende Geschichte sein. Es gibt mehr Dinge im Himmel und auf der Erde, Horatio, als in Ihrer Philosophie geträumt werden.
quelle
unsigned x
alsx = x >> 1;
das implementierungsdefinierte Verhalten, wennx < 0
. Unklar warumx
undOrMask
unterscheiden sich in der Art. Einfach genug, um mit einemwhile(x)
Test neu zu schreiben .% 2
Fall bitweise zu kompilieren&
. Ich habe dies gerade getestet und die Ergebnisse sind völlig gleich (VS2015, Release-Builds mit allen Optimierungen, sowohl x86 als auch x64). Die akzeptierte Antwort gibt dies auch für GCC an (geschrieben 2008).or
schneller als einand
Bit ist, auf keiner Plattform / jedem Compiler höchst unwahrscheinlich ist. Selbst wenn es eine so seltsame Plattform / Compiler-Kombination gäbe (und Sie weder diesen noch den Code zur Durchführung des Benchmarks veröffentlicht haben), wäre es eine schlechte Optimierungswette, wenn sich andere Compiler gleich verhalten würden. Wie ich schrieb, frage ich mich, auf welcher Plattform / welchem Compiler dies getestet wurde , da ich fast sicher bin, dass es nicht richtig gemessen wurde.Dies ist eine Fortsetzung der Diskussion mit @RocketRoy über seine Antwort , aber es könnte für jeden nützlich sein, der diese Ergebnisse vergleichen möchte.
tl; dr was ich gesehen habe, ist Roys Ansatz (
(0xFFFFFFFF == (x | 0xFFFFFFFE)
) nicht vollständigx & 1
als der optimiertmod
Ansatz , aber in der Praxis sollten die Laufzeiten in allen Fällen gleich ausfallen.Also habe ich zuerst die kompilierte Ausgabe mit dem Compiler Explorer verglichen :
Getestete Funktionen:
CLang 3.9.0 mit -O3:
GCC 6.2 mit -O3:
Hut ab vor CLang, es wurde klar, dass alle drei Fälle funktional gleich sind. Roys Ansatz ist jedoch in GCC nicht optimiert, so YMMV.
Ähnlich verhält es sich mit Visual Studio. Bei der Überprüfung der Demontage Release x64 (VS2015) auf diese drei Funktionen konnte ich feststellen, dass der Vergleichsteil für die Fälle "mod" und "und" gleich und für den Fall "Roy" oder "etwas größer" ist:
Nach dem Ausführen eines tatsächlichen Benchmarks zum Vergleichen dieser drei Optionen (einfacher Mod, bitweiser oder bitweiser und) waren die Ergebnisse jedoch vollständig gleich (wieder Visual Studio 2005 x86 / x64, Release Build, kein Debugger beigefügt).
Release Assembly verwendet die
test
Anweisung fürand
undmod
Fälle, während Roys Fall die verwendetcmp eax,0FFFFFFFFh
Ansatz verwendet, aber er ist stark abgerollt und optimiert, sodass es in der Praxis keinen Unterschied gibt.Meine Ergebnisse nach 20 Läufen (i7 3610QM, Windows 10-Energieplan auf Hochleistung eingestellt):
Der Unterschied zwischen diesen Optionen beträgt weniger als 0,3%, daher ist es ziemlich offensichtlich, dass die Baugruppe in allen Fällen gleich ist.
Hier ist der Code, wenn jemand es versuchen möchte, mit einer Einschränkung, dass ich ihn nur unter Windows getestet habe (überprüfen Sie die
#if LINUX
Bedingung für dieget_time
Definition und implementieren Sie ihn bei Bedarf, entnommen aus dieser Antwort ).quelle
Ich weiß, dass dies nur syntaktischer Zucker ist und nur in .net anwendbar ist, aber was ist mit der Erweiterungsmethode ...
Jetzt können Sie Folgendes tun
quelle
In der Kategorie "kreativ aber verwirrend" biete ich an:
Eine für Microsoft C ++ spezifische Variante dieses Themas:
quelle
Die bitweise Methode hängt von der inneren Darstellung der Ganzzahl ab. Modulo funktioniert überall dort, wo es einen Modulo-Operator gibt. Beispielsweise verwenden einige Systeme tatsächlich die Low-Level-Bits zum Markieren (wie dynamische Sprachen), sodass das rohe x & 1 in diesem Fall nicht wirklich funktioniert.
quelle
IsOdd (int x) {return true; }}
Korrektheitsnachweis - Betrachten Sie die Menge aller positiven ganzen Zahlen und nehmen Sie an, dass es eine nicht leere Menge von ganzen Zahlen gibt, die nicht ungerade sind. Da positive ganze Zahlen gut geordnet sind, gibt es eine kleinste nicht ungerade Zahl, die an sich ziemlich ungerade ist, so dass diese Zahl eindeutig nicht in der Menge enthalten sein kann. Daher darf dieser Satz nicht leer sein. Wiederholen Sie diesen Vorgang für negative Ganzzahlen, außer suchen Sie nach der größten nicht ungeraden Zahl.
quelle
Tragbar:
Unportable:
quelle
Wie einige Leute geschrieben haben, gibt es zahlreiche Möglichkeiten, dies zu tun. Laut dieser Website ist der Moduloperator der schnellste Weg:
Hier ist jedoch ein anderer Code, der als Benchmark markiert wurde vom Autor wurde und langsamer lief als die oben beschriebene übliche Moduloperation:
Wie viele Leute wussten überhaupt von der Math.System.DivRem- Methode oder warum sollten sie sie verwenden?
quelle
getan.
quelle
Um die bitweise Operatormethode für diejenigen von uns näher zu erläutern, die während unseres Studiums nicht viel Boolesche Algebra durchgeführt haben, finden Sie hier eine Erklärung. Wahrscheinlich nicht sehr nützlich für das OP, aber ich wollte klarstellen, warum NUMBER & 1 funktioniert.
Bitte beachten Sie, dass die Darstellung negativer Zahlen, wie oben beantwortet, die Funktionsweise dieser Methode beeinträchtigen kann. Tatsächlich kann es sogar die Modulo-Operator-Methode brechen, da sich jede Sprache darin unterscheiden kann, wie sie mit negativen Operanden umgeht.
Wenn Sie jedoch wissen, dass NUMBER immer positiv ist, funktioniert dies gut.
Wie Tooony oben betonte, ist nur die letzte Ziffer in Binär (und Denar) wichtig.
Ein boolesches logisches UND-Gatter schreibt vor, dass beide Eingänge eine 1 (oder Hochspannung) sein müssen, damit 1 zurückgegeben wird.
1 & 0 = 0.
0 & 1 = 0.
0 & 0 = 0.
1 & 1 = 1.
Wenn Sie eine Zahl als Binärzahl darstellen (ich habe hier eine 8-Bit-Darstellung verwendet), haben ungerade Zahlen am Ende 1, gerade Zahlen 0.
Beispielsweise:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Wenn Sie eine beliebige Zahl nehmen und bitweise UND (& in Java) mit 1 verwenden, wird entweder 00000001 = 1 zurückgegeben, was bedeutet, dass die Zahl ungerade ist. Oder 00000000 = 0, was bedeutet, dass die Zahl gerade ist.
Z.B
Ist ungerade?
1 & 1 =
00000001 &
00000001 =
00000001 <- Ungerade
2 & 1 =
00000010 &
00000001 =
00000000 <- Gerade
54 & 1 =
00000001 &
00110110 =
00000000 <- Gerade
Deshalb funktioniert das:
Entschuldigung, wenn dies überflüssig ist.
quelle
Zahl Null Parität | Null http://tinyurl.com/oexhr3k
Python-Codesequenz.
quelle
quelle
Zur Diskussion ...
Sie müssen nur die letzte Ziffer einer bestimmten Zahl betrachten, um festzustellen, ob sie gerade oder ungerade ist. Signiert, nicht signiert, positiv, negativ - diesbezüglich sind sie alle gleich. Das sollte also rundum funktionieren: -
Der Schlüssel hier befindet sich in der dritten Codezeile. Der Divisionsoperator führt eine ganzzahlige Division durch, sodass dem Ergebnis der Bruchteil des Ergebnisses fehlt. So ergibt beispielsweise 222/10 22. Dann multiplizieren Sie es erneut mit 10 und Sie haben 220. Subtrahieren Sie das vom Original 222 und Sie erhalten 2, was magisch die gleiche Zahl wie die letzte Ziffer in der ursprünglichen Zahl ist. ;-) Die Klammern erinnern uns an die Reihenfolge, in der die Berechnung durchgeführt wird. Führen Sie zuerst die Division und die Multiplikation durch und subtrahieren Sie dann das Ergebnis von der ursprünglichen Zahl. Wir könnten sie weglassen, da die Priorität für Division und Multiplikation höher ist als für Subtraktion, aber dies gibt uns "besser lesbaren" Code.
Wir könnten alles völlig unlesbar machen, wenn wir wollten. Für einen modernen Compiler würde es keinen Unterschied machen:
Aber es würde die Pflege des Codes in Zukunft erschweren. Stellen Sie sich vor, Sie möchten den Text für ungerade Zahlen in "ist nicht gerade" ändern. Dann möchte später jemand anderes herausfinden, welche Änderungen Sie vorgenommen haben, und einen SVN-Diff oder ähnliches durchführen ...
Wenn Sie sich nicht um die Portabilität, sondern um die Geschwindigkeit sorgen, können Sie sich das niedrigstwertige Bit ansehen. Wenn dieses Bit auf 1 gesetzt ist, ist es eine ungerade Zahl, wenn es 0 ist, ist es eine gerade Zahl. Auf einem kleinen Endian-System wie Intels x86-Architektur wäre es ungefähr so: -
quelle
Wenn Sie effizient sein möchten, verwenden Sie bitweise Operatoren (
x & 1
). Wenn Sie jedoch lesbar sein möchten, verwenden Sie modulo 2 (x % 2
).quelle
%
. Wenn Sie möchten, dass es lesbar ist, verwenden Sie%
. Hmmm, ich sehe hier ein Muster.Gerade oder ungerade zu überprüfen ist eine einfache Aufgabe.
Wir müssen nur die Teilbarkeit einer beliebigen Zahl überprüfen und zur Überprüfung der Teilbarkeit verwenden wir den
%
OperatorÜberprüfen Sie gerade ungerade mit, wenn sonst
C-Programm, um gerade oder ungerade zu überprüfen, wenn sonst
Verwenden des Bedingten / Ternären Operators
C-Programm zum Überprüfen von geraden oder ungeraden Werten mit dem bedingten Operator .
Verwenden des bitweisen Operators
quelle
+ 66% schneller>
!(i%2) / i%2 == 0
Der Code überprüft das letzte Bit der Ganzzahl, wenn es in Binär 1 ist
Erläuterung
Der Operator & bitwise AND überprüft das Bit ganz rechts in unserer Rückgabezeile , wenn es 1 ist
Betrachten Sie es als wahr und falsch
Wenn wir n mit 1 vergleichen , bedeutet dies
0001
binär (die Anzahl der Nullen spielt keine Rolle).Stellen wir uns dann vor, wir hätten die ganze Zahl n mit einer Größe von 1 Byte.
Es würde durch 8-Bit / 8-Binärziffern dargestellt.
Wenn der int n war 7 und wir vergleichen es mit 1 , Es ist wie
Welches F steht für falsch und T für wahr.
Was ist, wenn ich das Bit ganz rechts überprüfen möchte?
Ändern Sie einfach
n & 1
,n & 2
welche 2 darstellt0010
in Binär darstellt und so weiter.Ich schlage vor, die hexadezimale Notation zu verwenden, wenn Sie Anfänger in bitweisen Operationen sind
return n & 1;
>>return n & 0x01;
.quelle