Wie kann ich überprüfen, ob eine bestimmte Zahl in C gerade oder ungerade ist?
Wie kann ich überprüfen, ob eine bestimmte Zahl in C gerade oder ungerade ist?
Antworten:
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);
return 0;
}
/* 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);
return 0;
}
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.
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 ...
Verwenden Sie die Bitarithmetik:
if((x & 1) == 0)
printf("EVEN!\n");
else
printf("ODD!\n");
Dies ist schneller als die Verwendung von Division oder Modul.
[Witzmodus = "Ein"]
public enum Evenness
{
Unknown = 0,
Even = 1,
Odd = 2
}
public static Evenness AnalyzeEvenness(object o)
{
if (o == null)
return Evenness.Unknown;
string foo = o.ToString();
if (String.IsNullOrEmpty(foo))
return Evenness.Unknown;
char bar = foo[foo.Length - 1];
switch (bar)
{
case '0':
case '2':
case '4':
case '6':
case '8':
return Evenness.Even;
case '1':
case '3':
case '5':
case '7':
case '9':
return Evenness.Odd;
default:
return Evenness.Unknown;
}
}
[Witzmodus = "aus"]
BEARBEITEN: Der Aufzählung wurden verwirrende Werte hinzugefügt.
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:
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!
Eine schöne ist:
/*forward declaration, C compiles in one pass*/
bool isOdd(unsigned int n);
bool isEven(unsigned int n)
{
if (n == 0)
return true ; // I know 0 is even
else
return isOdd(n-1) ; // n is even if n-1 is odd
}
bool isOdd(unsigned int n)
{
if (n == 0)
return false ;
else
return 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!
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.
// Java
public static boolean isOdd(int num){
return num % 2 != 0;
}
/* C */
int isOdd(int num){
return num % 2;
}
Methoden sind großartig!
i % 2 == 0
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
Noch eine Lösung für das Problem
(Kinder können gerne wählen)
bool isEven(unsigned int x)
{
unsigned int half1 = 0, half2 = 0;
while (x)
{
if (x) { half1++; x--; }
if (x) { half2++; x--; }
}
return half1 == half2;
}
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:
typedef unsigned int uint;
char parity_uint [UINT_MAX];
char parity_sint_shifted [((uint) INT_MAX) + ((uint) abs (INT_MIN))];
char* parity_sint = parity_sint_shifted - INT_MIN;
void build_parity_tables () {
char parity = 0;
unsigned int ui;
for (ui = 1; ui <= UINT_MAX; ++ui) {
parity_uint [ui - 1] = parity;
parity = !parity;
}
parity = 0;
int si;
for (si = 1; si <= INT_MAX; ++si) {
parity_sint [si - 1] = parity;
parity = !parity;
}
parity = 1;
for (si = -1; si >= INT_MIN; --si) {
parity_sint [si] = parity;
parity = !parity;
}
}
char uparity (unsigned int n) {
if (n == 0) {
return 0;
}
return parity_uint [n - 1];
}
char sparity (int n) {
if (n == 0) {
return 0;
}
if (n < 0) {
++n;
}
return parity_sint [n - 1];
}
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) {
return 1;
}
}
return 0;
}
char odd (int n) {
int k;
for (k = INT_MIN; k <= INT_MAX; ++k) {
if (n == 2 * k + 1) {
return 1;
}
}
return 0;
}
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
und odd
hier präsentiert wird richtig für alle C-Zahlen arbeiten.
i % 2
ist viel kleiner und wahrscheinlich effizienter.
%2
funktioniert für alle ganzen Zahlen.
// C#
bool isEven = ((i % 2) == 0);
typedef
oder #define
oder etwas.
Hier ist eine Antwort in Java:
public static boolean isEven (Integer Number) {
Pattern number = Pattern.compile("^.*?(?:[02]|8|(?:6|4))$");
String num = Number.toString(Number);
Boolean numbr = new Boolean(number.matcher(num).matches());
return numbr.booleanValue();
}
Versuche dies: return (((a>>1)<<1) == a)
Beispiel:
a = 10101011
-----------------
a>>1 --> 01010101
a<<1 --> 10101010
b = 10011100
-----------------
b>>1 --> 01001110
b<<1 --> 10011100
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.
unsigned x
als x = x >> 1;
das implementierungsdefinierte Verhalten, wenn x < 0
. Unklar warum x
und OrMask
unterscheiden sich in der Art. Einfach genug, um mit einem while(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 ein and
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ändig x & 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:
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(unsigned int): # @isOdd_mod(unsigned int)
and edi, 1
mov eax, edi
ret
isOdd_and(unsigned int): # @isOdd_and(unsigned int)
and edi, 1
mov eax, edi
ret
isOdd_or(unsigned int): # @isOdd_or(unsigned int)
and edi, 1
mov eax, edi
ret
GCC 6.2 mit -O3:
isOdd_mod(unsigned int):
mov eax, edi
and eax, 1
ret
isOdd_and(unsigned int):
mov eax, edi
and eax, 1
ret
isOdd_or(unsigned int):
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 test
Anweisung für and
und mod
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):
[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 LINUX
Bedingung für die get_time
Definition und implementieren Sie ihn bei Bedarf, entnommen aus dieser Antwort ).
#include <stdio.h>
#if LINUX
#include <sys/time.h>
#include <sys/resource.h>
double get_time()
{
struct timeval t;
struct timezone tzp;
gettimeofday(&t, &tzp);
return t.tv_sec + t.tv_usec*1e-6;
}
#else
#include <windows.h>
double get_time()
{
LARGE_INTEGER t, f;
QueryPerformanceCounter(&t);
QueryPerformanceFrequency(&f);
return (double)t.QuadPart / (double)f.QuadPart * 1000.0;
}
#endif
#define NUM_ITERATIONS (1000 * 1000 * 1000)
// using a macro to avoid function call overhead
#define Benchmark(accumulator, name, operation) { \
double startTime = get_time(); \
double dummySum = 0.0, elapsed; \
int x; \
for (x = 0; x < NUM_ITERATIONS; x++) { \
if (operation) dummySum += x; \
} \
elapsed = get_time() - startTime; \
accumulator += elapsed; \
if (dummySum > 2000) \
printf("[Test: %-12s] %0.2f ms\r\n", name, elapsed); \
}
void DumpAverage(char *test, double totalTime, double reference)
{
printf("[Test: %-12s] AVERAGE TIME: %0.2f ms (Relative diff.: %+6.3f%%)\r\n",
test, totalTime, (totalTime - reference) / reference * 100.0);
}
int main(void)
{
int repeats = 20;
double runningTimes[3] = { 0 };
int k;
for (k = 0; k < repeats; k++) {
printf("Run %d of %d...\r\n", k + 1, repeats);
Benchmark(runningTimes[0], "Plain mod 2", (x % 2));
Benchmark(runningTimes[1], "Bitwise or", (0xFFFFFFFF == (x | 0xFFFFFFFE)));
Benchmark(runningTimes[2], "Bitwise and", (x & 1));
}
{
double reference = runningTimes[0] / repeats;
printf("\r\n");
DumpAverage("Plain mod 2", runningTimes[0] / repeats, reference);
DumpAverage("Bitwise or", runningTimes[1] / repeats, reference);
DumpAverage("Bitwise and", runningTimes[2] / repeats, reference);
}
getchar();
return 0;
}
Ich weiß, dass dies nur syntaktischer Zucker ist und nur in .net anwendbar ist, aber was ist mit der Erweiterungsmethode ...
public static class RudiGroblerExtensions
{
public static bool IsOdd(this int i)
{
return ((i % 2) != 0);
}
}
Jetzt können Sie Folgendes tun
int i = 5;
if (i.IsOdd())
{
// Do something...
}
In der Kategorie "kreativ aber verwirrend" biete ich an:
int isOdd(int n) { return n ^ n * n ? isOdd(n * n) : n; }
Eine für Microsoft C ++ spezifische Variante dieses Themas:
__declspec(naked) bool __fastcall isOdd(const int x)
{
__asm
{
mov eax,ecx
mul eax
mul eax
mul eax
mul eax
mul eax
mul eax
ret
}
}
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.
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.
Wie einige Leute geschrieben haben, gibt es zahlreiche Möglichkeiten, dies zu tun. Laut dieser Website ist der Moduloperator der schnellste Weg:
if (x % 2 == 0)
total += 1; //even number
else
total -= 1; //odd number
Hier ist jedoch ein anderer Code, der als Benchmark markiert wurde vom Autor wurde und langsamer lief als die oben beschriebene übliche Moduloperation:
if ((x & 1) == 0)
total += 1; //even number
else
total -= 1; //odd number
System.Math.DivRem((long)x, (long)2, out outvalue);
if ( outvalue == 0)
total += 1; //even number
else
total -= 1; //odd number
if (((x / 2) * 2) == x)
total += 1; //even number
else
total -= 1; //odd number
if (((x >> 1) << 1) == x)
total += 1; //even number
else
total -= 1; //odd number
while (index > 1)
index -= 2;
if (index == 0)
total += 1; //even number
else
total -= 1; //odd number
tempstr = x.ToString();
index = tempstr.Length - 1;
//this assumes base 10
if (tempstr[index] == '0' || tempstr[index] == '2' || tempstr[index] == '4' || tempstr[index] == '6' || tempstr[index] == '8')
total += 1; //even number
else
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
}
Entschuldigung, wenn dies überflüssig ist.
Zahl Null Parität | Null http://tinyurl.com/oexhr3k
Python-Codesequenz.
# 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
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);
}
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: -
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: -
if (iToTest & 1) {
// Even
} else {
// Odd
}
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
).
%
. 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 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
Überprüfen Sie gerade ungerade mit, wenn sonst
if(num%2 ==0)
{
printf("Even");
}
else
{
printf("Odd");
}
C-Programm, um gerade oder ungerade zu überprüfen, wenn sonst
Verwenden des Bedingten / Ternären Operators
(num%2 ==0) printf("Even") : printf("Odd");
C-Programm zum Überprüfen von geraden oder ungeraden Werten mit dem bedingten Operator .
Verwenden des bitweisen Operators
if(num & 1)
{
printf("Odd");
}
else
{
printf("Even");
}
!(i%2) / i%2 == 0
int isOdd(int n)
{
return n & 1;
}
Der Code überprüft das letzte Bit der Ganzzahl, wenn es in Binär 1 ist
Binary : Decimal
-------------------
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 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
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
7 (1-byte int)| 0 0 0 0 0 1 1 1
&
1 (1-byte int)| 0 0 0 0 0 0 0 1
********************************************
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 & 1
ist T rue.
Ä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;
.