Code-Optimierung anhand von „FizzBuzz“

Profil

geschrieben von Ejder-Deniz Ceri

veröffentlicht am 16. September 2022

Header-Image

Was ist „FizzBuzz"?

„FizzBuzz" ist eine klassische Programmieraufgabe für Anfänger. Sie wird hauptsächlich für Übungszwecke oder in Einstellungstests verwendet.

Die Aufgabe ist folgende:

Schreibe ein Programm, das die Zahlen von 1 bis 100 ausgibt.

Jedoch, wenn die Zahl durch drei teilbar ist, soll anstelle der Zahl das Wort „Fizz" ausgegeben werden.

Und wenn die Zahl durch fünf teilbar ist, soll anstelle der Zahl das Wort „Buzz" ausgegeben werden.

Wenn eine Zahl sowohl durch drei als auch durch fünf teilbar ist, soll das Wort „FizzBuzz" ausgegeben werden.



Eine mögliche Lösung in Javascript wäre:

// die for- Schleife zählt die variable i von 1 bis 100 hoch for ( let i =1 ; i <=100 ; i++ ) { // hier wird überprüft ob die zahl in i sowohl durch 3 als auch durch 5 teilbar ist // der gemeinsame Teiler ist 15. So kann man sich eine interne Logik wie // z.B.: i%3 == 0 && i%5 == 0 sparen. if (i%15 === 0)
console.log("FizzBuzz"); // wenn die zahl nicht durch 15 teilbar ist wird überprüft ob sie durch 3 bzw, 5 teilbar // ist. else if ((i%3) === 0) console.log("Fizz");
else if ((i%5) === 0)
console.log("Buzz");
// Wenn all das nicht zutrifft, dann wird im else-Fall die Zahl ausgegeben. else console.log( i );
}

Damit zeigt man, dass man grundlegende Programmierkenntnisse in Bezug auf Schleifen, Konditions-abfragen und auch den Modulo-Operator beherrscht.

So wäre die Sache ja auch erledigt, aber der Algorithmus ist nicht unbedingt der Effizienteste.

Sehen wir uns nun mal eine andere Implementierung an.

// Als erstes legen wir drei Variablen an. Die erste Variable ist ein leerer // String gefolgt von zwei Zähler Variablen.

let s = ""; let c3 = 0, c5 = 0;

// Genauso wie oben lassen wir die i Variable auf 100 hochzählen

for (let i = 1; i <= 100; i++) { // Bei jeder Iteration der Schleife erhöhen wir die Werte der Zählvariablen c3 und c5. c3++; c5++;

// nun vergleichen wir den Wert von c3 mit der Zahl 3 und wenn diese erfüllt ist hängen wir // das „Fizz“-Wort an den leeren String und setzen den c3 Zähler wieder auf 0. if (c3 === 3) { s += "Fizz"; c3 = 0; } // das gleiche machen wir mit dem c5 zähler und der Zahl 5 und hängen beim erfüllen der // Kondition das Wort „Buzz“ an unserem String an. if (c5 === 5) { s += "Buzz"; c5 = 0; }

// Jetzt überprüfen wir, ob unser String Variable noch leer ist. Wenn dem so ist waren die // vorrangigen Konditionen der if-Abfragen nicht erfüllt worden und deshalb geben wir unsere // Schleifenvariable i aus. // Wenn jedoch die String Variable nicht leer ist, geben wir eben diesen aus. // Als letztes leeren wir die Stringvariable s wieder.

if (s.length === 0)
    console.log(i);
else
    console.log(s);
    s = "";

}

Die Frage ist jetzt, warum der zweite Algorithmus überhaupt verwendet werden sollte. Besonders, weil dieser ja mehr Variablen braucht als der erste.

Um die Antwort nachvollziehbarer zu machen, gehen wir auf die Kern-Differenz der beiden Algorithmen ein. Der Grund, warum der zweite Algorithmus bevorzugt werden soll, ist, weil sie auf den Modulo Operator verzichtet.



Der Modulo Operator ( % ) berechnet den Rest einer Division.

Zum Beispiel 5 / 2 = 2 rest 1 ==> 5 % 2 = 1

Das heißt, damit der Rest berechnet werden kann, muss vorher eine Division berechnet werden. Das macht den Modulo Operator für die CPU besonders rechenintensiv.

Im zweiten Algorithmus dagegen wird nur addiert und verglichen, diese Operationen sind für die CPU besonders „einfach", weil die CPU verhältnismäßig nur wenige Instruktionen mit geringer Latenz ausführen muss.

Wir sehen, viele Wege führen nach Rom, manche schneller, andere länger. So muss auch immer evaluiert werden, ob eine Lösung nach Geschwindigkeit oder Speicherbedarf optimiert werden soll oder ob eine Optimierung überhaupt notwendig ist. Schließlich hat auch unsere erste Lösung seinen Zweck erfüllt.


Bild von Boskampi auf Pixabay.

Author

Ejder-Deniz Ceri

Ein Projekt im Sinn?

Sprecht uns an!