Feststellen, ob eine Zahl ungerade / gerade ist

Oft möchte man in der täglichen Web-Programmier-Praxis feststellen, ob eine Zahl gerade oder ungerade ist (gerade = durch 2 ganzzahlig teilbar). Ich selbst gebrauche das gern, um Übersicht in Artikellisten zu schaffen, indem ich abwechselnd die Hintergrundfarbe mal heller und mal etwas dunkler darstelle. Das ist wesentlich übersichtlicher als die Variante alle mit gleichem Hintergrund aufzulisten. Wie nun aber prüft man möglichst performant, ob eine Zahl gerade oder ungerade ist?

Ich möchte kurz alle hier zu testenden Varianten vorstellen:

 
// Variante 1 - die Amateurhafte  
$o = 0;
 for($i=0;$i<1000;$i++) { 
  echo $i." ist ";
  $o++; 
  if($o==1) echo "ungerade"; 
  else {  
  echo "gerade"; 
   $o=0;  
 }  
 }    
// Variante 2 - die Mathematische  
for($i=0;$i<1000;$i++) {
   echo $i." ist "; 
 if($i%2) echo "ungerade"; 
  else 
 echo "gerade";
  } 
// Variante 3 - die Binäre  
for($i=0;$i<1000;$i++) { 
 echo $i." ist ";
 if($i & 1) echo "ungerade"; 
  else
  echo "gerade"; 
}    
// Variante 4 - die Kurze 
 for($i=0;$i<1000;$i++) { 
   echo $i." ist "; 
  echo ($i & 1)?"ungerade":"gerade";
 } 

Die 1. Variante ist sicherlich nicht oft umgesetzt, wird aber oft von Anfängern als erster Vorschlag geliefert. In diesem Fall wird eine zweite Zählvariable mitgeführt, die zwischen 1 und 2 rangiert (sicherlich kommt sie auch auf 0, das ist aber nicht relevant für die Überprüfung, ob eine Zahl gerade ist). Aber das ständige Inkrementieren und Zurücksetzen kostet unnötig Zeit, zumal wir ja bereits eine Zählvariable von der for-Schleife haben – und die sollten wir dann auch nutzen.

In der 2. Variante wird die Modulo-Operation genutzt. Diese gibt den ganzzahligen Rest einer Division zurück. Es ist demzufolge klar, dass wenn bei der Division durch 2 ein Rest bleibt, dass die Zahl dann ungerade ist. Und weil in PHP true==1 kann man die if-Abfrage ohne Vergleich schreiben.

Die 3. Variante kann nur von einem Informatiker stammen ????
Hierbei wird die binäre Operation & 1 ausgeführt. Dazu wird die letzte Stelle der Zählvariable in Binärschreibweise mit 1 und-verknüpft (wichtig hierbei: nicht && schreiben, da das lediglich Prüfen würde, ob $i > 0!). Ist die letzte Stelle eine 0, so ergibt 0 & 1 = 0. Ist sie eine 1, so ist 1 & 1 = 1 (0 steht hierbei für false und 1 für true). Und genau das ist das gewünschte Ergebnis, da die letzte Binärstelle für 20 zuständig ist und demzufolge exakt definiert, ob die Zahl gerade oder ungerade ist.
Diese Variante folgt wohl dem Motto

There are 10 types of people: those who understand binaries and those who don’t

????

Die 4. Variante hat nur den Zweck den trinären Operator (=Konditionaloperator) zu testen. Die Logik ist die gleiche wie bei Variante 3, könnte aber genauso gut mit dem Modulo-Operator umgesetzt werden. Vorteil dieser Variante ist, dass der Code sehr schön kurz ist.

So, nun genug Theorie, hier sind die Ergebnisse.

Datei Gesamtlaufzeit durchschnittliche Laufzeit pro Durchlauf Verhältnis zur schnellsten Variante
ungerade_binary.php 24.785640 s 2.479 ms 100 %
ungerade_mod.php 25.486648 s 2.549 ms 103 % (+ 3%)
ungerade_binary_ trinaer.php 26.718419 s 2.672 ms 108 % (+ 8%)
ungerade_counter.php 26.838592 s 2.684 ms 108 % (+ 8%)

Am schnellsten in die Binär-Und-Verknüpfung. Das ist auch nicht weiter verwunderlich, da die (meisten) heutigen Rechner nunmal im Binärmodus arbeiten und somit damit auch am schnellsten zurechtkommen. Die Modulo-Operation ist etwas langsamer, aber noch akzeptabel.
Etwas überrascht hat mich die Performance des trinären Operators. Hätte gedacht, dass dieser nicht nur kurz sondern auch flott ist, aber dem ist nicht so. Werde dann also in Zukunft lieber „richtige“ if-else-Reihen aufbauen.
Und nicht überraschend ist die Langsamkeit der zusätzlichen Zählvariable. Auch wenn diese Variante genauso langsam ist wie mit dem Konditionaloperator, habe ich sie rot markiert, weil sie einfach anfängerhaft ist und in keinem Projekt vorkommen sollte. Dazu kommt noch, dass sie zusätzlichen Speicher verschwendet durch die zusätzliche Variable.


Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0