Universität Hamburg - Fachbereiche - Fachbereich Mathematik

Java-Kurs (6)

Numerische Mathematik, WiSe 99/00 und SoSe 00, Bodo Werner

Zurück zum Inhaltsverzeichnis.

Lineare Gleichungssysteme

Die Klasse LGS

Zweidimensionale Felder, Exceptions (Fehler abfangen, try, catch, throw)
Reelle (n x n)-Matrizen werden in Java mit zweidimensionalen Feldern dargestellt, deren Deklaration und Allokierung etwa durch double[][] A = new double[n][n] oder ohne new z.B. durch double[][] A={{1,2,3},{-2,3,0},{2,3,-1}}; erfolgt.

In der linearen Algebra werden die Zeilen und Spalten einer (m x n)-Matrix von 1 bis m und 1 bis n durchnumeriert. In Java werden dagegen die Komponenten der Felder (z.B. double[][] A= new double[m][n]; ) bei 0 beginnend und bei m-1 bzw. n-1 endend indiziert. Auf diese wird mit A[i][j] i=0,1,...,m-1, j=0,1,...,n-1 zugegriffen. Bei allen Java-Implementierungen von Algorithmen der numerischen Linearen Algebra muss man also meist einen (ärgerlichen) Shift der Indizes durchführen.

Man kann auch nichtrechteckige Felder allokieren. Z.B. durch

int n=5;
double[][] A = new double[n][];
for(int j=0;j<n;j++) A[j]= new double[j+1];
oder durch
double[][] A={{1},{1,2},{1,2,3}};
werden dreieckige Felder in Form unterer Dreiecksmatrizen allokiert.

Exceptions

Es gibt sehr strukturierte Möglichkeiten, Laufzeitfehler aufzufangen, ohne dass das Programm zwingend abbricht. Die häufigsten Laufzeitfehler, die bisher auftraten, sind z.B. IndexOutOfBoundsException beim versehentlichen Zugriff auf Komponenten von Feldern außerhalb der definierten Grenzen oder NullPointerException, wenn ein Objekt nur deklariert, aber nicht allokiert wurde, aber dennoch auf dessen Daten oder Methoden zugegriffen wird, oder auch ArithmeticException, etwa bei (int-) Division durch Null. Alle diese Laufzeitfehler sind Unterklassen der Klasse Exception. Wenn diese Fehler auftreten, wird die Ausführung des Programms mit einer entsprechenden Meldung des Fehlertyps abgebrochen.

Dies kann mit der try-catch-Anweisung verhindert werden. Durch die catch-Anweisung wird der Fehler "behandelt". Zuvor kann er mit Hilfe einer throw-Anweisung auch "weitergegeben" werden. Eine genauere Erörterung dieser Fehlerbehandlung kann hier nicht erfolgen, sondern muss in einem Lehrbuch nachgelesen werden. Ich werde mich hier mit Beispielen begnügen:

1 class fehler1{
2   static double w(double x) throws Exception{
3     if (x<0) throw new Exception>("Das Argument "+x+" ist negativ!");
4     return Math.sqrt(x);
5   }
6   static void main(String[] args){
7    try{
8     for(int i=0;i<h;10;i++)
9     System.out.println(w(Math.sin(i*3.1)));
10   }
11   catch(Exception e){System.out.println(e);}
12  }//Ende main()
13}//Ende class fehler1
In Zeile 2 wird durch throws Exception die "Weitergabe" eines Fehlers des allgemeinen Typs Exception angekündigt, der in Zeile 3 definiert wird, wenn das Argument der "Wurzel"-Methode w() negativ ist (ohne diese "Ausnahmeweitergabe" würde der Wert NaN in Zeile 5 zurückgegeben werden). Der Konstruktor von Exception (Zeile 3) sieht die Übergabe eines Strings vor, der in Zeile 11 ausgegeben wird. Genauer: Jedes Java-Objekt kennt die Methode String toString(), die immer zur Anwendung kommt, wenn das Objekt als Parameter von System.out.println() auftritt. Vielleicht wird dies klarer, wenn man eine eigene Fehlerklasse, z.B. durch
class EigenerFehler extends Exception{
 String Grund;
 EigenerFehler(String Grund){
   this.Grund=Grund;
 }//Ende Konstruktor
 public String toString(){
  return Grund;
 }//Ende Ueberlagerung von toString()
}//Ende class EigenerFehler
definiert, den man etwa durch throw new Eigenerfehler("Pivotelement verschwindet"); weitergeben kann.

Nun zur try-catch-Anweisung. Falls in Zeile 9 der Aufruf von w() zu einem Fehler (in Zeile 3) führt, wird dieser "behandelt", indem der try-Block sofort verlassen und die catch-Anweisung in Zeile 11 angesteuert wird, sofern der aufgetretene Fehler von dem Typ ist, der in den runden Klammern hinter catch steht. Hier ist dies der Fall, weil unser Fehler vom allgemeinsten Typ Exception ist. Ausgeführt wird dann der catch-Block (hier eine Ausgabe des Fehlers samt mit ihm verbundener in Zeile 3 festgelegten "individuellen" Text). Danach würde das Programm in Zeile 12 fortfahren, ein Abbruch wie bei einem nicht behandelten Laufzeitfehlers findet also nicht statt, es sei denn, der catch-teil enthält den Befehl System.exit(1);.

Das folgende Beispiel behandelt den Laufzeitfehler ArithmeticException:

for (int j=-3;j<3;j++)
try{
System.out.println(1/j);
}
catch(ArithmeticException e){System.out.ptintln(e);}
Dieser Programmteil würde zu der folgenden Ausgabe führen:
0
0
-1
java.lang.ArithmeticException: / by zero
1
0

Grundsätzlich könnten Fehlerbehandlungen auch konventionell mit Hilfe vieler Verzweigungen (if, switch) erfolgen. Das hier geschilderte Vorgehen hat den Vorteil, dass Verzweigungen nur zur Ablaufsteuerung des Algorithmus verwendet werden.

Im Kap.4 über lineare Gleichungssysteme werden wir die hier besprochene Fehlerbehandlung u.a. auf das Auftreten verschwindender Pivotelemente beziehen.

Hier geben wir einen Auszug der Klasse LGS wieder, die ebenfalls nur statische Methoden enthält:

public class LGS{
    //Alle Routinen mit Ueberschreibung der Felder
    //Es geht nur um quadratische Matrizen    
    static int n; //Dimension 
   
    //Im folgenden wird a ueberschrieben (Kein Zeilentausch):    
  public static  void LRZerlegung(double[][] a) throws Exception{ 
    n=a.length; 
    for(int k=0;k=0;k--){
      for (int j=n-1;j>=k+1;j--) b[k]-=R[k][j]*b[j];
      b[k]/=R[k][k];
    }//Ende k
  }//Ende rw()

    public static void LoeseLGS(double[][] a,double[] b){
    try{
       	LRZerlegung(a);
	vw(a,b);
        rw(a,b);
    }
    catch(Exception e){
	System.out.println(e);System.exit(1);
    }
    }//Ende LoeseLGS()
    

  public static void main(String[] args){
      //Test:
     double[][] A1={{4,-1,2,0},{-1,3,1,-1},{1,0,5,3},{0,-1,0,2}};
     double[] b1={5,2,9,1};
     LoeseLGS(A1,b1); //Loesung ist (1,1,1,1)
     for (int k=0;k<=3;k++) System.out.println(b1[k]);
  }//Ende main()
}//Ende class LGS

Für die nachfolgenden numerischen Probleme (Lineare Optimierung, Lineare Ausgleichsprobleme, nichtlineare Gleichungen und Gleichungssysteme) wurden keine neuen Javaaspekte behandelt. Daher fehlen hier entsprechende Demonstrationsprogramme.