Programmieren

Programmier-Fallstricke

 aufwärts

Ein großer Teil der Programmier­fehler geht darauf zurück, dass Programmierer die Semantik der verwendeten Programmier­sprache nicht genau beachten. Dies ist einerseits Schuld der Programmierer, andererseits vielfach aber auch Schuld der Entwickler der Programmier­sprache, die Miss­verständnisse sozusagen "vor­programmiert" haben.

Die folgenden Beispiele betreffen die Programmier­sprache Java (und gleichermaßen C++); in anderen Programmier­sprachen gibt es andere Fallstricke.

Die Zeichen +, - und *

Die meisten Programmierer gehen davon aus, dass die Zeichen +, -, * und / die vier Grund­rechenarten Addition, Subtraktion, Multi­plikation und Division bedeuten. Natürlich ist dies meistens richtig, manchmal aber auch falsch. In C++ und Java bedeutet etwa das Zeichen + bei int-Werten keine normale Addition, sondern eine Addition modulo 232. Das Ent­sprechende gilt für - und *.

Niemand erwartet, dass die Multi­plikation der beiden positiven int-Zahlen 46000 und 47000 eine negative Zahl ergibt. Es gibt keine Fehler­meldung "Überlauf des Zahlen­bereichs", sondern es wird modulo 232 gerechnet.

public class TestMult
{
    public static void main(String[] args)
    {
        long a;
        a=46000*47000;
        System.out.println(a);
    }
}

Selbst die Tatsache, dass die Variable a als long deklariert ist, nützt nichts. Die Zahlen­konstanten 46000 und 47000 werden als int-Werte angesehen und modulo 232 multi­pliziert. Das Ergebnis ist ein negativer int-Wert, dieser wird bei der Wert­zuweisung an die Variable a in den Typ long umgewandelt.

 

Mittelwert

Der Mittelwert zweier Zahlen a und b berechnet sich mathematisch als (a + b)/2.

public class Mittelwert
{
    public static void main(String[] args)
    {
        int a=2000000000;
        int b=1000000000;
        System.out.println((a+b)/2);
    }
}

Das Ergebnis ist nicht wie erwartet 1500000000, sondern es wird ein negativer Wert berechnet. Dies liegt daran, dass bei der Bildung der Summe a+b der int-Zahlen­bereich über­schritten worden ist.

Um den Mittelwert korrekt zu berechnen, ist die kompliziertere Formel a+(b-a)/2 erforderlich.

 

Das Zeichen /

Das Zeichen / bedeutet bei int-Werten keine normale Division, sondern eine ganzzahlige Division mit Rest. In folgendem Programm soll die double-Variable a den Wert 0.5 erhalten, aber das Ergebnis ist 0.0.

public class TestDiv
{
    public static void main(String[] args)
    {
        double a=1/2;
        System.out.println(a);
    }
}

Die ganze Zahl 1 wird ganzzahlig durch 2 geteilt; das Ergebnis ist 0 Rest 1. Das Ergebnis 0 wird in die double-Zahl 0.0 umgewandelt.

 

Noch einmal das Zeichen +

Der Umfang eines Rechtecks mit den Kantenlängen a und b beträgt 2*a + 2*b. Das folgende Programm berechnet als Umfang des Rechtecks mit den Kantenlängen a = 4 und b = 17 den Wert 834.

public class Umfang
{
    public static void main(String[] args)
    {
        int a=4, b=17;
        System.out.println("Der Umfang beträgt " + 2*a+2*b);
    }
}

Das Problem besteht darin, dass in Java das Zeichen + sowohl für die Addition von Zahlen als auch für die Verkettung von Zeichen­ketten (Strings) verwendet wird. In dem Beispiel werden die Strings "Der Umfang beträgt", 2*a und 2*b verkettet, wobei die Zahlenwerte 2*a und 2*b automatisch in Strings umgewandelt werden. Um ein korrektes Ergebnis zu erzielen, muss der Ausdruck 2*a+2*b in Klammern gesetzt werden.

 

Rundung

Bei Rechnungen mit dem Datentyp double ist es wichtig zu berück­sichtigen, dass es zu Rundungs­fehlern kommen kann. Insbesondere ist ein Vergleich if (x==0) äußerst problematisch, denn wenn x als Ergebnis einer Berechnung zustande gekommen ist, so ist es meist aufgrund von Rundungs­fehlern keineswegs gewähr­leistet, dass x exakt gleich Null ist, auch wenn es dies eigentlich sein sollte. So kann x zum Beispiel gleich 1.1E-16 = 0.00000000000000011 sein, also praktisch gleich Null, aber nicht exakt gleich Null.

Nie sollte man also so programmieren:

    double a, b;
    a=2;
    b=0.4;
    while (a!=0)
        a=a-b;

Das Programm­stück sieht harmlos aus: b wird von a fünfmal subtrahiert, dann ist der Wert 0 erreicht und die Schleife sollte abbrechen. In Wirklichkeit handelt es sich um eine Endlos­schleife, denn a wird nicht exakt gleich Null. Das Programm bleibt also in dieser Schleife hängen und ist damit "abgestürzt".

Daher dürfen double-Werte nie mit den Vergleichs­operatoren == und != miteinander verglichen werden.

Mit b=0.5 funktioniert das obige Programm. Warum?

 

Zahlenkonstanten

Zum Schluss folgt noch ein besonders krasses Beispiel für ein vor­programmiertes Miss­verständnis in Java. Probieren Sie aus, welchen Wert folgendes Java-Programm ausgibt:

public class Test
{
    public static void main(String[] args)
    {
        double a;
        a=023l;
        System.out.println(a);
    }
}

Das Ergebnis ist offenbar 231. So sollte man jedenfalls denken. Tatsächlich ist das Ergebnis aber 19. Der Computer hat nichts falsch gemacht, sondern einerseits der Programmierer, der statt einer 1 versehentlich ein kleines "L" geschrieben hat. Angehängt an die Zahl 023 wird es als Typ­kennzeichner für den Typ long aufgefasst. Und andererseits der Entwickler der Programmier­sprache, der die Ent­scheidungen getroffen hat, dass ein kleines "L" zulässig ist und, schlimmer noch, dass eine führende 0 anzeigt, dass die Zahl als Oktalzahl, also als Zahl zur Basis 8 (hier 2·8 + 3·1 = 19), zu interpretieren ist.1)


1)  Wahrscheinlich wurde dies schon beim Entwurf einer Vorläufer­sprache von C festgelegt, denn Oktalzahlen wurden nur in der Frühzeit der Daten­verarbeitung benutzt. Man kann sich förmlich vorstellen, wie es dazu gekommen ist. Irgendjemand wollte unbedingt oktal dargestellte Zahlen­konstanten haben. Ein voran­gestellter Buchstabe zur Kenn­zeichnung der oktalen Darstellung, vielleicht ein kleines "o", wäre am deutlichsten gewesen, aber dann wäre z.B. o23 als Variablen­name zu interpretieren gewesen. Ein nach­gestelltes Zeichen ging auch nicht, da der Compiler die Zahl schon als Dezimalzahl ausgewertet hat, wenn er auf das nach­gestellte Zeichen trifft. Die Sonder­zeichen waren schon alle für Operatoren verbraucht, also blieb nur eine Ziffer. Und so kam es zu der "Vereinbarung" (der ich als Programmierer nie zugestimmt hätte), dass eine führende 0, die ja an ein "O" wie oktal erinnert, die Inter­pretation der Zahl als Oktalzahl anzeigt. Hiervon abgeleitet ist wohl auch die sonderbare Kenn­zeichnung für hexadezimal dargestellte Zahlen­konstanten durch "0x", also "0 extended". Dies wäre auch die Lösung für Oktalzahlen gewesen: "0c" als Kenn­zeichnung für octal und dann auch gleich noch "0b" für binär.

 

Weiter mit:   up

 

homeH.W. Lang   Hochschule Flensburg   lang@hs-flensburg.de   Impressum   Datenschutz   ©   Created: 06.04.2005   Updated: 20.06.2018
Valid HTML 4.01 Transitional

Hochschule Flensburg
Campus Flensburg

Informatik in Flensburg studieren...

 

Neu gestaltetes Studienangebot:

Bachelor-Studiengang
Angewandte Informatik

mit Schwerpunkten auf den Themen Software, Web, Mobile, Security und Usability.

Ihr Abschluss
nach 7 Semestern:
Bachelor of Science

 

Ebenfalls ganz neu:

Master-Studiengang
Angewandte Informatik

Ein projektorientiertes Studium auf höchstem Niveau mit den Schwerpunkten Internet-Sicherheit, Mobile Computing und Human-Computer Interaction.

Ihr Abschluss
nach 3 Semestern:
Master of Science

 

Weitere Informatik-Studienangebote an der Hochschule Flensburg:

Medieninformatik

Wirtschaftsinformatik