PHP For Beispiel 3: Summenberechnung mit Gleitkommazähler

Die For-Schleife kann nicht nur mit ganzzahligen Zählervariablen verwendet werden. Auch der Einsatz von Gleitkommavariablen als Zähler ist möglich. Im nächsten Beispiel wird eine solche Variable verwendet. Hier wird wieder die Variable zur Speicherung der Summe initialisiert. Nach der Ausgabe einer Zeichenkette, die über die Funktion echo erfolgt, wird eine For-Anweisung mit einem Gleitkommazähler implementiert.

Der Schleifenkopf initialisiert die Zählervariable i mit dem Wert 0. Als Abbruchkriterium dient der Ausdruck i < 1, was bedeutet, dass i solange erhöht wird, bis der dort gespeicherte Wert den Wert 1 erreicht oder gar überschritten hat. Die Schrittweite wird im letzten Teil des For-Statements mit Hilfe des Ausdrucks i+=0.2 festgelegt. Dies bedeutet, dass i nach jedem Schleifendurchgang um 0.2 erhöht wird.

Im Schleifenkörper, der hier mit den geschweiften Klammern eingefasst werden muss, da zwei Anweisungen im Schleifenkörper ausgeführt werden sollen, wird jeweils der in sum gespeicherte Summenwert berechnet und die zum jeweiligen Durchgang berechnete Summe sowie der in i gespeicherte Wert ausgegeben. Nach dem letzten Schleifendurchgang wird ein HTML-Tag zur Darstellung eines Zeilenumbruchs ausgegeben. Zum Schluss wird der Endwert der Variable sum zusammen mit einer beschreibenen Zeichenkette (String) ausgegeben.

<?php
    // Variable zur Summenberechnung zurücksetzen
    $sum = 0;
    // Zeichenkette ausgeben
    echo 'Wertepaare von sum und j: ';
    // Diesmal wird die Schleife von 0 bis < 1 in der Schrittweite 0.2
    // laufen.
    for ($i = 0; $i < 1; $i += 0.2) {
        // Wieder aufsummieren
        $sum += $i;
        // diesmal aber die einzelnen Werte in Wertepaaren ausgeben
        echo '(' . $sum . ', ' . $i . ')';
    }
    // Zeilenumbruch bzw. HTML-Code für einen Zeilenumbruch ausgeben
    echo '<br>';
    // Berechnete Summe ausgeben
    echo 'Summe (Schrittweite 0.2): ' . $sum;
?>

Wertepaare von (sum, j): (0, 0)(0.2, 0.2)(0.6, 0.4)(1.2, 0.6)(2, 0.8)
Summe (Schrittweite 0.2): 2

PHP For Beispiel 4: Abbruchbedingung bei Vergleich mit Float

Das nächste Beispiel unterscheidet sich kaum vom vorangegangenen. Lediglich die Veränderug der Zählervariablen wird hier mit einer anderen Schrittweite angepasst. Der letzte, in der Ausgabe des Scripts weiter unten aufgeführte, Schleifendurchgang erfolgt mit einem Zählerwert von 1 – siehe letztes ausgegebenes Wertepaar (5.5,1).

Aufgrund der formulierten Abbruchbedingung ist dieses Verhalten allerdings nicht erwünscht. Dennoch liefert der Ausdruck für die Abbruchbedingung bei i < 1 den Wert TRUE. Dieses Verhalten hängt mit der internen Speicherung von Werten zusammen. Die Variable i wird als Float-Wert die Konstante 1 allerdings liegt als Integer-Wert vor. Da diese Werte beiderseits intern als binäre Werte gespeichert sind, kann es sein, dass die Werte nicht präzise in binärer Form dargestellt werden können. Bei Integer-Werten ist dies kein Problem, da jeder ganzzahlige Wert in Binärer Darstellung präzise dargestellt werden kann. Anders sieht es bei Gleitkommazahlen aus. Hier kann es zu Ungenauigkeiten bei der binären Speicherung der Daten kommen – vgl. auch 1/3 im Dezimalsystem entspricht als Gleitkommazahl 0,333...; auch hier ist eine genaue Darstellung nicht möglich.

Während dies beim letzten Beispiel möglich war, stösst das folgende Beispiel an diese Genauigkeitsgrenze. Nach dem letzten Durchgang der Schleife enthält i eben nicht wie erwartet den Wert 0.9 und wird auf 1.0 erhöht – was zum Abbruch der Schleifenverarbeitung führt –, sondern einen Wert Nahe 0.9 (etwa 0.8999999...). Dies hat zur Folge, dass die Schleife nocheinmal mit i gleich 1 (genauer gesagt 0.9999999...) ausgeführt wird. Die Abbruchbedingung hat hier etwa die Form 0.999999999 < 1, was TRUE liefert – die Schleife wird einmal häufiger durchlaufen.

<?php
    // Und wieder zurücksetzen
    $sum = 0;
    echo 'Wertepaare von (sum, i): ';
    // Jetzt läuft i von 0 bis < 1 mit einer Schrittweite von 0.1
    for ($i = 0; $i < 1; $i += 0.1) {
        $sum += $i;
        echo '(' . $sum . ',' . $i . ')';
    }
    // und wieder einen Zeilenumbruch
    echo '<br>';
    // Summenwert ausgeben
    echo 'Summe (Schrittweite 0.1): ' . $sum;
?>

Wertepaare von (sum, i): (0,0)(0.1,0.1)(0.3,0.2)(0.6,0.3)(1,0.4)(1.5,0.5)(2.1,0.6) (2.8,0.7)(3.6,0.8)(4.5,0.9)(5.5,1)
Summe (Schrittweite 0.1): 5.5

Verhindert werden kann dieses Verhalten nur durch den Einsatz von Typkonvertierungen oder durch eine vorherige Transformation oder Normierung der Gleitkommawerte. Grundsätzlich sollten Gleitkommazahlen bei Vergleichen – egal ob sie in If-Statements oder als Abbruchbedingung bei Schleifen verwendet werden – nie auf Gleichheit geprüft werden. Im unteren Beispiel wird die Funktion round verwendet, um den in i gespeicherten Wert auf die erste Nachkommastelle zu runden. Round liefert diesen gerundeten Wert zurück und vergleicht ihn mit dem Wert 1.

<?php
    // Summenvariable zurücksetzen
    $sum = 0;
    echo 'Wertepaare von (sum, i): ';
    // Runden auf die erste Stelle nach dem Komma
    for ($i = 0; round ($i, 1) < 1; $i += 0.1) {
        $sum += $i;
        echo '(' . $sum . ',' . $i . ')';
    }
    // Zeilenumbruch
    echo '<br>';
    // Summenwert ausgeben
    echo 'Summe (Schrittweite 0.1): ' . $sum;
?>

Wertepaare von (sum, i): (0,0)(0.1,0.1)(0.3,0.2)(0.6,0.3)(1,0.4)(1.5,0.5)(2.1,0.6)(2.8,0.7) (3.6,0.8)(4.5,0.9)
Summe (Schrittweite 0.1): 4.5

¬ Tutorials



¬ Insolvenzrecht