# Ist eine Zahl gerade?



## mamarulez (22. Dezember 2003)

Hallo!

ich hab mal eine kurze Frage:

ich habe eine Funktion mit zugehöriger Hauptschleife geschrieben, was einfach untersucht ob eine Zahl gerade oder nicht gerade ist.

Hier kommt erstmal der Quelltext:


```
bool IstZahlGerade ( int Zahl )
{
	int		i;
	for ( i = 0; i <= 1000; i = i += 2 )
	{
		if	( i == Zahl )
		return true;
		else
		return false;
	}
}

void main ( void )
{
	//AufPrimzahlTesten ( 2, 10 );
	if ( IstZahlGerade ( 4 ) == true) cout<<"4 ist gerade\n";
	else cout<<"4 ist ungerade\n";
}
```

Also, mein Problem ist, dass im Programm die Zahl 4 als ungerade bezeichnet wird! Anscheinend heist es, dass alle Zahlen ungerade seien, da ich, als ich später die 5 einsetzte es auch (diesmal zufällig richtig!) hieß, dass auch 5 ungerade sei.

Kann mir wer helfen?

Danke im Vorraus!


----------



## Fabian H (22. Dezember 2003)

Wieso nicht einfach mit:

```
int iNum = 5;
if (iNum % 2 == 0) {
    printf( "%i ist gerade", iNum );
} else {
    printf( "%i ist nicht gerade", iNum );
}
```


----------



## mamarulez (22. Dezember 2003)

g.

danke dass du einem vollkommenem idioten geholfen hast. +

*selbst-auf-den-schädel-hau*

mann bin ich blöd...

vielen dank!


----------



## Thomas Darimont (23. Dezember 2003)

Servus!

Geht auch so:


```
#include <iostream>
#include <stdlib.h>

using namespace std;

int main(int argc, char *argv[])
{
for (int i = 0; i < 10000;i++){
    cout << "i: " << i << " ist gerade: " << !(i & 1) << "\n" ;
}
  system("PAUSE");	
  return 0;
}
```

Gruß tom


----------



## Aziz (23. Dezember 2003)

Zu überprüfen ob eine Zahl gerade oder ungerade ist, geht ganz einfach. Man braucht nur überprüfen ob das erste Bit 1 oder 0 ist. Das funktioniert aber ausschließlich bei Datentypen, die nur ganze Zahlen darstellen können (w.z.B. int, long, short, __int64 etc.). D.h. bei floats und doubles würde das nicht funktionieren, da diese Datentyp eine spezielle Formatierung im Speicher haben. Auch wenn eine Variable dieses Datentyps eine gerade Zahl enthält würde es höchstwahrscheinlich nicht funktionieren. Ist aber nur eine Annahme; verwendet aber zur Sicherheit Datentypen, die für ganze Zahlen da sind.

Warum funktioniert das?

Nun lasst uns einfach die Zahlen 0 -15 in Binär aufschreiben:

0000 =  0
0001 =  1
0010 =  2
0011 =  3
0100 =  4
0101 =  5
0110 =  6
0111 =  7
1000 =  8
1001 =  9
1010 = 10
1011 = 11
1100 = 12
1101 = 13
1110 = 14
1111 = 15

Wenn wir genau hinschauen, dann bemerken wir, dass das erste Bit bei allen geraden Zahlen 0 ist, und bei ungeraden Zahlen 1.

Deine IstZahlGerade-Funktion müsste daher folgendermaßen aussehen:


```
bool IstZahlGerade ( int Zahl )
{
  if( (Zahl & 1) == 0)
    return true;
  else
    return false;
}
```
Wir brauchen das erste Bit einfach nur mit einer binären Und-Operation isolieren, und auf 0 prüfen. Falls das zutrifft ist die Zahl gerade.
Man bezeichnet das, was in der If-Abfrage in den Klammern steht auch als "Maskierung". Ich gebe dir zwei Beispiele dazu:

Wenn ich eine binäre Zahl, 0110 0101 (8Bit, könnte ein character sein), habe und die höherwertigen 4 Bits isolieren wollte, dann müsste ich diese Zahl einfach mit 1111 0000 und-verknüpfen. Das Ergebnis wäre 0110 0000.

Oder wenn du folgende Zahl hast: 1001 1011 1101 0011 und das niederwertige Byte erhalten willst, dann musst du diese Zahl mit 0000 0000 1111 1111 und-verknüpfen.
Das Ergebnis: 0000 0000 1101 0011

Wir sehen also, dass bei einer Und-Verknüpfung die 0 immer "gewinnt".


----------



## Bypass41 (23. Dezember 2003)

Hi,

was ist denn mit Modulus ?


----------



## Aziz (23. Dezember 2003)

Ich denke mit dem Modulus sollte es auch funktionieren, aber die Methode die ich angeführt habe finde ich persönlich besser, da sie sicher schneller bearbeitet wird. Eine Und-Verknüpfung macht jeder Prozessor mit Links (es ist praktisch ein eigener Hardwarebefehl), aber im Vergleich dazu wird jeder Prozessor bei einer Modulu-Operation ein wenig länger brauchen. Nehme ich zumindest an.

Es ist klar, dass nicht bei jeder Anwendung Schnelligkeit wichtig ist, aber davon zu wissen ist ja sicherlich was Gutes.


----------



## Maximka (23. Dezember 2003)

@Aziz:
Wenn man %2 (sprich Modulo 2) schreibt, ist der Compiler schon schlau genug und wandelt es dir in den von dir beschriebenen &1 (sprich bitweise UND mit 1) um. Beide Methoden sind also identisch und damit auch gleich schnell


----------



## Aziz (23. Dezember 2003)

Danke für die Aufklärung.


----------



## Bypass41 (23. Dezember 2003)

Und man weniger zu schreiben. Softwareentwickler sind faul. ;-)


----------



## chibisuke (24. Dezember 2003)

Des weiteren wird Modulo auch durch die hardware berechnet.

das DIV komando liefert das Ergebnis und den Rest der Division zurück.


----------



## mamarulez (25. Dezember 2003)

so. das problem wäre gelöst.

klasse arbeit!


----------



## Kachelator (30. Dezember 2003)

Nachtrag, für den OP:


```
for ( i = 0; i <= 1000; i = i += 2 )
```
Guck dir mal das Ende des Schleifenkopfes an: 
i = i += 2 
Da ist eine Macke drin. Da wird zu oft zugewiesen.

[ot]
Wie nennt man eigentlich die drei Bestandteile der for-Anweisung? Also die Statements, die innerhalb der runden Klammer durch Semikolons getrennt werden?
[/ot]


----------



## basd (30. Dezember 2003)

Die richtigen Namen hab ich grad nicht parat
- "initialisierung der Schleife" ==  Anweisung vor Eintritt, "Voranweisungen"  (i=0)
- Laufbedingung (auch für den Eintritt in den Schleifenkörper beim ersten mal relevant), muss einen Logischen Wert zurück liefern, wenn TRUE schleifen Körper durchgeführt, sonst break
- Schleifenkörper Endanweisung , Anweisung die nach Ablauf des Schleifenkörpers {} ausgeführt wird bevor eine erneute Untersuchung der Schleifenlaufbeduingung erfolgt

Die Folgenden sachen sind identisch

for (A; B ; C)
{
  D;
}

 ==

A;
while(B)
{
 D;
 C;
}


----------



## Kachelator (31. Dezember 2003)

> Schleifenkörper Endanweisung



Hm, mir kam diese Nacht noch der Ausdruck "Fortzählungsausdruck" in den Sinn.

Jedenfalls vielen Dank!


----------



## Radhad (4. Januar 2004)

also, wir nennen das Zweite die Bedingung und das Dritte die Schrittweite, das Erste könnte man Startpunkt nennen...


----------



## basd (4. Januar 2004)

Eigentlich ist nur die Bedingung wichtig  + Man muss wissen das der linke Teil vor Eintritt einmal durchgeführt wird  und der rechte Teil nach jedem Durchlauf der Scheife durchgeführt wird.
Der linke Teil und der Rechte müssen nicht unbedingt was mit einem Schleifenzaaehler zu tun haben ... wurde aber halt so eingeführt weil man oft schleifen von x bis y durchläuft in z schritten.
z.B.:

double Ergebnis;
double  diff = 1.0;
double x ;
double y ;

for(Ergebnis = 0.0,  x = 2.0, y= 0.0 ;  diff  > 0.05; Ergebnis = y )
{
   DoWeirdStuffToInterpolateSqRoot(x, & y);
   diff = y*y - x ;
}

So würde zum Beispiel eine Interpolation mit einer bestimmten Genauigkeit (hier unschö weil man nicht den tatsächlichen Fehler untersucht ! ) aussehen


----------

