Mathpack als 2D-Disp-Demo
Auch Computer kommen ohne Zahlen klar
Das System Mathpack gestattet den Aufbau eigener Elemente, die den
Gesetzen der Mathematik unterliegen. So können ohne weitere Probleme
komplexe Zahlen, Vektoren oder auch Matritzen in einfachen Ausdrücken
bearbeitet werden. Um den Anwender nicht bei Null beginnen zu lassen, ist
eine Arithmetik beigefügt, die jederzeit erweitert, geändert
oder entfernt werden kann. Die folgenden Seiten beschäftigen sich
mit dem Aufbau dieser Arithmetik und bilden so die Grundlage für eigene
Erweiterungen.
Mathpack stellt prizipiell nur einen Rahmen zur Verfügung, innerhalb
dessen sich die vom Benutzer definierten Objekte bearbeiten lassen. Objekt
ist auch das erste Stichwort, denn zunächst muß geklärt
werden um was sich der Benutzer denn alles kümmern soll. Am einfachsten
scheint die Bereitstellung einer Zahl zu sein, denn Computer gehen ja
ausschlie�ich mit diesen "Dingern" um.
Zahlen
Ob es sich bei einer Zeichenfolge um eine Zahl handelt kann leider nicht
ohne Weiteres gesagt werden. Die Zahlenbasis ist zu beachten, Vorzeichen
und vielleicht auch ein Komma oder ein Dezimalpunkt. All diese Kleinigkeiten
müssen beachtet werden, um von einer Zeichenfolge sagen zu können:
Das ist eine Zahl.
Glücklicherweise stellt JavaTM
hier bereits viele Möglichkeiten bereit, die Zeichenfolgen in Zahlen
umwandeln. Die Klassifizierung von Zahlen wird eben diese bereitgestellten
Möglichkeiten nutzen, womit bereits die erste Klasse aufgebaut werden
kann. Die elementaren Methoden dieser Klasse sind vorgeschrieben und müssen
vorhanden sein. Es handelt sich um zwei Methoden; die eine eine erzeugt
ein (Zahlen)Objekt aus einer Zeichenfolge, die andere überprüft,
ob die Zeichenfolge in eine Zahl gewandelt werden kann. Das Aussehen dieser
beiden Methoden ist festgelegt in
mathpack/values/anyValue.java
Ob weitere Methoden nötig oder sinnvoll sind, obliegt dem Anwender.
Wenn eigene Objekte für Werte erzeugt werden sollen, muss zunächst
eine Klasse dieser Objekte entworfen werden. Die hier besprochene Arithmetik
benutzt eine in Java
TM bereits vorhandene
Klasse namens Double. Es wird also eine Klasse definiert, die
unbedingt die beiden erwähnten Methoden in der vorgeschriebenen Form
(interface) benutzt. Begonnen wird mit der Testmethode t.
public boolean t( String str) {
try
{
new Double( str);
return true;
}
catch( NumberFormatException nfe)
{
return false;
}
} |
Im try-Part wird einfach ein neues Double-Object instanziert.
Weil dieses jedoch aus den bereits besprochenen Gründen schiefgehen
könnte, wird der Protest, der von Java
TM
in Form einer NumberFormatException vorgebracht wird, im catch-Part
abgefangen. In Kurzfassung:
Versuche aus der Zeichenfolge ein Double-Object zu erzeugen.
Wenn es gelungen ist, verlasse die Methode mit true.
Wenn eine NumberFormatException aufgefangen wurde, verlasse
die Methode mit false. |
Für alle anderen Java
TM-internen Wertobjekte
(Integer, short, ...) funktioniert diese Vorgehensweise
ebenfalls. Natürlich muß dann statt Double eben die
entsprechende Klassenbezeichnung eingesetzt werden. Obwohl hier bereits
ein entsprechendes Objekt erzeugt wurde, ist eine explizite Instanzierung
vorgeschrieben. Die Instanzierung eines Objekts das Zahlen repäsentiert,
ist durch die Methode c vorgeschrieben. Genau wie bei der vorangegangenen
Methode muß auch c vom Benutzer ausdrücklich spezifiziert
werden.
public Object c( String str) {
return new Double( str);
} |
Es wird ein Object übergeben, das einfach aus der intern
erzeugten Instanz einer Klasse namens Double hergestellt wurde.
Wenn der Anwender eine andere Klasse als Zahl vereinbart, wird eben diese
instanziert. Die Methoden um aus einer Zeichenfolge das Objekt einer Zahl
herzustellen stehen jetzt fest. Es fehlt noch die Klassifizierung und damit die
universelle Bereitstellung eines Zahlenobjektes. Hier ist der Benutzer
alleiniger Herrscher über die Namens- und Ortsvergabe.
Klasse der Werte
Bei dem Entwurf dieser Klasse ist zu berücksichtigen, dass zwei Methoden
zwingend vorhanden sein müssen. Beide Methoden wurden im letzten Abschnitt
hergeleitet und müssen in eine Klasse für allgemeine Wertangaben
integriert werden. Die entsprechende Klasse im Arithmetik-Paket wird eingeleitet
durch
public class value implements mathpack.values.anyValue { |
Das Schlüsselwort public erklärt diese Klasse als allgemein
verfügbar. Gefolgt von class, das die Klassifizierung einleitet.
Anschließend folgt der Name der Klasse (nicht etwa die Bezeichnung
eines Objekts) value. Dieser Name kann vom Benutzer frei vergeben
werden. Zwei Methoden sollen zwingend sein, was durch implements
und die Ortsangabe des Pakets erfolgt. Zusammengefügt ergibt sich
nun die elementare Klasse für Zahlenwerte des Objekttyps Double
zu folgendem Bild:
//**************************************/
//*
*/
/** Klasse aller Werte einer Grammatik */
//*
*/
//**************************************/
public class value implements mathpack.values.anyValue {
//*************************************************************/
/** Test auf Validierbarkeit eines Zeichenfolge (hier Double)
*/
//*************************************************************/
public boolean t( String str) {
try
{
Double dbl;
dbl = new Double( str);
return true;
}
catch( NumberFormatException nfe)
{
return false;
}
}
//**************************************************/
/** Instanzierung eines Wertelements (hier Double) */
//**************************************************/
public Object c( String str) {
return new Double( str);
}
} |
Es ist nicht sofort erkenntlich, warum ein Objekt auf diese umständliche
Art klassifiziert wird, jedoch mit etwas Geduld kann dieser Weg nachvollzogen
werden. Das System Mathpack arbeitet mit Objekten und es ist dem System
völlig egal, welche Objekte es benutzt. Dem Anwender ist diese Gleichgültigkeit
aber nicht zuzumuten, weshalb eine Schnittstelle zwischen dem was der Benutzer
meint und dem was das System bearbeitet, bereitgestellt werden muss. Genau
diese Schnittstelle wurde soeben in ihrer minimalsten Form fertiggestellt.
Die Benutzung dieser Klasse ist relativ einfach und verdeutlicht etwas
den Schnittstellengedanken. Angenommen die Zeichenfolge 123.45
soll als Wertobjekt über die eben hergeleitete Klasse als Zahl erstellt
werden. Zunächst wird eine Ortsangabe benötigt, unter der die
Klasse zu finden ist.
import mathpack.arithmetic.*; |
leistet hier den entsprechenden Dienst. Es folgen die Formalien, die jeder
Programmiersprache innewohnen um ein Programm zu starten. Hier soll etwas
getestet werden, weshalb die Programmsequenz den treffenden Namen test
erhält. Das Hauptprogramm trägt die vorgeschriebene Bezeichnung
main.
import mathpack.arithmetic.*;
public class test {
public static void main( String args[]) {
}
} |
Dieses Schema (abgesehen von der ersten Zeile) kann für alls möglichen
Tests zugrunde gelegt werden. Jedenfalls soll jetzt zwischen den geschweiften
Klammern bei main eine Zeichenfolge verfügbar gemacht werden. Mit
ist diese Hürde genommen. Jetzt folgt die Instanzierung des entworfenen
Objekts mit der Klassenbezeichnung value. Der Name des Objekts soll zahl
sein. Eine Zeile mit
value zahl = new value(); |
erledigt diese Aufgabe. Es fehlt nur noch ein Objekt, das den eigentlichen
Wert 123.45 enthält. Dieses Objekt muss aber universelle Gültigkeit
besitzen. Somit bleibt nur
Über die Instanz der Werteklasse value, die hier die Bezeichnung
zahl
trägt, wird zunächst die Zeichenfolge auf Wandlungsfähigkeit
überprüft. Je nachdem, ob aus die Folge eine Zahl gewandelt werden
kann, soll eine entsprechende Ausgabe auf der Systemebene erfolgen. Sehr
skizzenhaft etwa
if (zahl.t( folge))
// then (für Verwirthe)
System.out.println(
"Klappt");
else System.out.println( "Klappt nicht"); |
Angenommen es klappt, dann kann das Objekt des Wertes mit der Instanzierungsmethode
c erzeugt werden, was ungefähr folgendes Aussehen hat:
Jetzt wurde endlich ein Wertobjekt aufgebaut, das den intern die Zahl 123.45
besitzt. Intern deshalb, weil ein Objekt aber keine nackte Zahl vorhanden
ist. Zwar liefert deine print( objekt)-Anweisung die ursprüngliche
Zeichenfolge 123.45, aber der Veruch den Wert (objekt + 5)
auszurechenen, wird an der Syntax (Typenverletzung) scheitern. Die Zahl
wird erst durch eine Typenwandlung und eine entsprechende Methode zugänglich.
Glücklicherweise ist der Typ von objekt bekannt es handelt
sich um ein Double-Object. Um aus objekt ein Double-Object
zu machen, bedarf es einer Typenwandlung der Form
Eine andere Wandlung ist nicht möglich, weil die Methode c
zwar den Typ Object liefert, dieser aber auf alle Instanzen von
Java
TM zurifft. die umgekehrte Wandlung
erfolgt nur, wenn die Typen instanzmäßig ubereinstimmen. Ein
Double-Object
hat eine eigene Methode ihren Wert mitzuteilen, sie lautet doubleValue().
Die Kombination aus Typenwandlung und Methodenaufruf erschließt den
Wert.
double wert = ((Double)objekt).doubleValue(); |
Eine Zusammenfassung des bisher Erreichten liefert zwar kaum Einblicke
in das System Mathpack, schafft aber die Grundlagen für den nächsten
Schritt, der sich mit der Benutzung von klassenexternen Methoden auseinandersetzt.
Doch zunächst die Zusammenfassung als Testprogramm.
import mathpack.arithmetic.*;
public class test {
public static void main( String args[]) {
String folge = "123.45"; // könnte
eine Zahl sein
value zahl = new value(); // erzeugt Wertobjekte
Object objekt = null;
// irgendein Objekt
System.out.print( "Die Zeichenfolge: " + folge + " kann ");
if (zahl.t( folge))
System.out.print( "ohne Weiteres
"); // geht ja wohl
else System.out.print( "nicht ");
// geht nicht
System.out.println( "gewandelt werden.");
if (!zahl.t( folge)) System.exit(0);
// hat sowieso keinen Sinn mehr
objekt = zahl.c( folge);
// Instanzieren
System.out.println( "
Das Objekt " + objekt + " wurde instanziert.");
System.out.println( "
Objektwert " + ((Double)objekt).doubleValue());
}
} |
Damit nun nicht für jede Berechnung die umständliche Typenwandlung
mit anschließendem Methodenaufruf durgeführt werden muss, ist
in der Klasse value des Pakets mathpack.arithmetic noch eine Hilfsmethode enthalten.
Sie übernimmt die Umwandlung in den spezifizierten Typ vor und liefert
den Wert selbst.
public static double getValue( Object obj) {
return ((Double)obj).doubleValue();
} |
Die letzte Zeile des Beispielprogramms könnte nun vereinfacht werden
zu
System.out.println( " Objektwert
" + zahl.getValue( objekt)); |
Der eigentliche Sinn dieser Objekthascherei liegt jedoch noch etwas tiefer.
Wenn ein System mit Objekten gleich welcher Art hantieren, gleichzeitig
aber Rücksicht auf spezielle Eigenschaften nehmen soll, müssen
dem System die individuellen Eigenschaften extern mitgeteilt werden.
Die Pakete
Eine sammlung von Java-Programmen zur Bearbeitung mathematischer Gleichungen.
Es umfasst die Eingabe von Funktionstermen, deren Berechnung und grafischen
Darstellung. Auf konsequente Auslegung auf Lauffähigkeit in Applets
gängiger Browser (sog. Vierer-Versionen) wurde geachtet. Das umfangreiche
Paket ist jedoch keinesfalls nur für die simple Darstellung elementarer
Funktionsverläufe ausgelegt, sondern als Einstieg in die symbolische
Algebra.
Die Eingabe eines Strings der Form "4+5", kann zur Folge eine sofortige
Berechnung, eine Umwandlung in die umgekehrt-polnische-Notation oder eine
Repräsentation als Objekt nach sich ziehen. Hinter dieser, auf den
ersten Blick wenig verheißungsvollen Aussage, steckt jedoch mehr
als vermutet. Wie reagiert ein herkömmliches Programm (kein Compiler),
das mit einem String wie
f(x) = 2*sin(a*x)/(cos(x)-b) |
konfrontiert wird? Wahrscheinlich mit einer Fehlermeldung. Mag x noch
als Variable und 2 noch als Literal erkannt werden, so treten doch bei
a und b erste Probleme auf. Eine interaktive Definition dieser beiden Größen
nach Übersetzung des Programms ist oft nur auf simple Wertzuweisungen
beschränkt. Dafür ist jedoch die Existenz von a und b als Variablen
im übersetzten Programm Voraussetzung. Mathpack geht hier einen anderen
Weg.
Die Behandlung von einfachen Gleichungen ist zunächst ein interpretierender
Vorgang, wie bei allen gängigen Programmen dieser Art auch. Der Unterschied
liegt tiefer. Praktisch jedes Element eines Ausdrucks kann vom Benutzer
selbst entworfen werden. Die Erstellung eigener Algebren, eigener Werte
(wer schreibt denn vor, daß 2 eine Dezimalzahl ist?), eigener Funktionen
usw. ist möglich. Jeder arithmetisch gültige (Sub)Term kann als
eigenständig ausführbares Objekt benutzt werden. Folgen derartiger
Objekte können so eigenständige Programme bilden und in andere
Projekte integriert werden.
Das gesamte, hier vorgestellte, System umfasst drei Bereiche: mathpack,
graphpack
und gui. Für die einheitliche Interagtion der zwei Beispielapplets
wurde noch die Klasse GridApplet beigefügt. Eine javadoc aller
Klassen ist natürlich dabei. Trotzdem sollen in den folgenden
Abschnitten wesentliche Teile des gesamten Pakets detailliert besprochen
werden.
mathpack
Diese Paket gestattet den bereits erwähnten Entwurf eigener Arithmetiken.
Detailliert auf die einzelnen Packages einzugehen würde zu weit führen,
weshalb hier nur die essentiellen Punkte kurz angesprochen werden.
arithmetic
Ist praktisch die Menge aller benutzerdefinierten zulässigen Operatoren,
Funktionen. In der hier beigefügten Arithmetik sind boolsche
Werte den "normalen" gleichwertig. So können Ausdrücke
der Form
berechnet werden, ohne jedesmal die H-Funktion bemühen zu müssen.
Entsprechende Änderungen können vom Benutzer natürlich gemacht
werden.
constants, variables
Diese beiden Klassen sind, ähnlich wie bei Java, um fast identisch.
Beide benutzen eine Klasse namens namedValue. Konstanten und Variablen
sind prinzipiell nur Werte die einen Namen haben. Welcher Art die Werte
sind (integer, double, complex, vector) ist Sache des Benutzers. Beide
verkörpern Mengen; entweder die Menge aller Konstanten, oder die aller
Variablen eines Ausdrucks.
operators, functions
Auch hier handelt es sich wieder um Mengen. Allerdings sind sie der Arithmetilk
untergeordnet und nicht dem Ausdruck.
grammar
Die Grammatik - es gibt bestimmt eine zutreffendere Bezeichnung - integriert
die genannten Mengen. Außerdem stellt sie Methoden bereit, die feststellen,
ob es sich bei dem Argument um Elemente einer bestimmten Menge handelt.
So würde z.B. der Aufruf
den Wert "true" liefern.
expression
Ein Ausdruck umschließt und benutzt praktisch die genannten Objekte.
Außerdem sind rudimentäre Syntaxprüfungen integriert. Mehrere
Ausdrücke lassen sich zu Objekten verbinden, die dann als Programme
lauffähig sind. Erwähnenswert ist, daß jeder Ausdruck seine
eigene, unabhängige Grammatik und auch Laufzeitumgebung besitzen kann.
graphpack
So interessant Mathematik auf der arithmetischen Ebene auch sein mag, richtig
rund wird die Sache erst wenn die Ergebnisse in grafischer Form vorliegen.