Bakkalaureus der technischen Wissenschaften - Ein UPN-Taschenrechner in C#

Die Seite wird erstellt Cornelia Hempel
 
WEITER LESEN
Ein UPN-Taschenrechner in C#

                           BAKKALAUREATSARBEIT
                                (Projektpraktikum)

                       zur Erlangung des akademischen Grades

             Bakkalaureus der technischen Wissenschaften
                               in der Studienrichtung

                                    INFORMATIK

Eingereicht von:
Andreas Vida, 0155987

Angefertigt am:
Institut für Systemsoftware (SSW)

Betreuung:
Dipl.­Ing. Markus Löberbauer

Linz, Juni 2006
Inhaltsverzeichnis
1 Spezi kation                                                                                  2
  1.1 Projektziel . . . . . . . . . . . . . . . . . . . . . . . .   .   .   .   .   .   .   . 2
  1.2 Systemvoraussetzungen . . . . . . . . . . . . . . . .         .   .   .   .   .   .   . 2
  1.3 Features der UPN Bibliothek . . . . . . . . . . . . .         .   .   .   .   .   .   . 2
      1.3.1 Berechnung mit frei wahlbarer Prazision . . .         .   .   .   .   .   .   . 2
      1.3.2 Verwendung von Aliasen fur Rechenvorgange             .   .   .   .   .   .   . 2
      1.3.3 Eingebaute Funktionen . . . . . . . . . . . .           .   .   .   .   .   .   . 4
  1.4 Features des UPN Taschenrechners . . . . . . . . . .          .   .   .   .   .   .   . 5
      1.4.1 Serialisierung des Stapels und der Metadaten            .   .   .   .   .   .   . 5
      1.4.2 Die gra sche Benutzerober ache . . . . . . .           .   .   .   .   .   .   . 5
  1.5 Bedienung des UPN-Rechners . . . . . . . . . . . . .          .   .   .   .   .   .   . 7
      1.5.1 Bedienungsbeispiele . . . . . . . . . . . . . .         .   .   .   .   .   .   . 8
  1.6 Fehlerbehandlung im Rechner . . . . . . . . . . . . .         .   .   .   .   .   .   . 10
  
2 Uberlegungen zur Losung der Teilprobleme                                                     11
  2.1 Berechnung von Post xausdrucken . . . . . . . . . .          .   .   .   .   .   .   .   11
      2.1.1 Stapelabarbeitung . . . . . . . . . . . . . . .         .   .   .   .   .   .   .   11
      2.1.2 Baumdarstellung eines Post xausdrucks . . .             .   .   .   .   .   .   .   12
      2.1.3 Umwandlung der Notation . . . . . . . . . .             .   .   .   .   .   .   .   14
      2.1.4 Baumauswertung . . . . . . . . . . . . . . . .          .   .   .   .   .   .   .   15
      2.1.5 De nition und Auswertung von Aliasen . . .              .   .   .   .   .   .   .   18
  2.2 Arithmetik mit beliebig groen Zahlen . . . . . . . .         .   .   .   .   .   .   .   19
      2.2.1 Reprasentation . . . . . . . . . . . . . . . . .       .   .   .   .   .   .   .   19
      2.2.2 Basenkonvertierung . . . . . . . . . . . . . .          .   .   .   .   .   .   .   19
      2.2.3 Grundrechenarten . . . . . . . . . . . . . . .          .   .   .   .   .   .   .   20
      2.2.4 Hohere Funktionen . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   21
      2.2.5 Darstellung von Nachkommastellen . . . . . .            .   .   .   .   .   .   .   23
      
  2.3 Uberlegungen   zur Modularisierung . . . . . . . . . .        .   .   .   .   .   .   .   24
  2.4 Austauschbarkeit von Number Klassen . . . . . . . .           .   .   .   .   .   .   .   25
  2.5 Parser fur Post xausdrucke . . . . . . . . . . . . . .      .   .   .   .   .   .   .   25
  2.6 Aufgaben der GUI . . . . . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   26
      2.6.1 Tastatureingaben verwalten, und verarbeiten             .   .   .   .   .   .   .   26
      2.6.2 Automatische Eingabekorrektur . . . . . . . .           .   .   .   .   .   .   .   27
      2.6.3 Ausklappbare Fenster . . . . . . . . . . . . .          .   .   .   .   .   .   .   27
      2.6.4 Benutzung der Zwischenablage . . . . . . . .            .   .   .   .   .   .   .   27
      2.6.5 Popupfenster versus Fenster mit Titelleisten .          .   .   .   .   .   .   .   28
      2.6.6 Look and Feel der GUI . . . . . . . . . . . .           .   .   .   .   .   .   .   28
  2.7 Zustandsserialisierung mit XML . . . . . . . . . . .          .   .   .   .   .   .   .   28
  2.8 Testen der Bibliothek und der Arithmetikklassen . .           .   .   .   .   .   .   .   31
3 Dokumentation der Implementierung                                                             31

                                        1
4 Kritische Beurteilung                                                      32
   4.1 Vergleich mit vorhandenen Produkten . . . . . . . . . . . . . . . 32
   4.2 Mogliche Verbesserungen . . . . . . . . . . . . . . . . . . . . . . 32

1 Spezi kation
1.1 Projektziel
Ziel des Projekts ist der Entwurf und die Realisierung einer Bibliothek zum
Rechnen mit Ausdrucken in umgekehrter (polnischer) Notation. Die Bibliothek
soll ein Interface anbieten, welches anderen Applikationen eine einfache Aus-
wertung von komplexen mathematischen Ausdrucken ermoglicht. In der Folge
soll im Rahmen dieses Projekts eine erste Anwendung dieser Bibliothek in Form
eines Rechners mit gra scher Benutzerober ache realisiert werden.
    Die Ober ache soll schlank und mit der Tastatur ezient zu bedienen sein.
Ziel dabei ist es eine bessere Usability und Ezienz zu erreichen, als die des
standardmaigen Taschenrechners im Zubehor von Microsoft Windows. Kon-
kret sollen Rechenergebnisse schnell wiederverwendet werden konnen. Je nach
Benutzerbedarf konnen Bedienelemente angepat werden, um etwa Platz am
Bildschirm zu sparen. Die zu verwendende Programmiersprache ist C#.

1.2 Systemvoraussetzungen
Minimalvorraussetzung zur Ausfhrung des Endproduktes ist das Betriebssystem
Windows 98 mit installiertem .NET Framework 1.1. Das Produkt sollte somit
auch auf leistungsschwachen PCs laufen.

1.3 Features der UPN Bibliothek
1.3.1 Berechnung mit frei wahlbarer Prazision
Die Bibliothek soll mit beliebig groen Zahlen arbeiten konnen (arbitrary pre-
cision arithmetic). Die Implementierungen der Grundoperationen und die Art
der Reprasentation von Zahlen sind austauschbar. In der Grundaustattung der
Bibliothek kann man entweder mit IEEE Gleitkommawerten rechnen (double),
oder mit der eigens fur dieses Projekt entwickelten arbitrary precision Klasse.

1.3.2 Verwendung von Aliasen fur Rechenvorgange
Der Bibliothek soll es ermoglichen, uberall wo Operanden erwartet werden Va-
riablen zu verwenden. Variablen konnen zu jeder Zeit mit verschiedenen Werten
belegt werden, was zur Folge haben kann, dass manche Ausdrucke am Stack
nicht sofort ausgewertet werden konnen. Die zu erzeugende Bibliothek verwen-
det statt Variablen das Konzept eines Alias. Letzterer kann nicht nur einen
einzigen numerischen Wert annehmen, sondern er reprentiert vielmehr einen

                                       2
Rechenvorgang, also eine Kette, aufgebaut aus einzelnen eingebauten Opera-
toren, Zahlen und anderen Aliasen. Eine Variable ist also ein Spezialfall eines
Alias, welcher nur einen numerischen Wert enthalt. Mit diesem Konzept kann
der Benutzer eigene Funktionen de nieren.
    Aliasnamen sind case-sensitive und eindeutig. Sie bestehen nur aus Buchsta-
ben des englischen Alphabets und durfen nicht den gleichen Namen tragen, wie
ein eingebauter Operator oder ein anderer Alias.

                                      3
1.3.3 Eingebaute Funktionen
 Funktion                                  Notiert als   Anmerkung
 Grundrechenarten
 Addition                                       +
 Subtraktion                                    -
 Multiplikation                                 *
 Division                                       /
 Absolutbetrag                                 abs
 Floor                                         int       ganzzahliger Anteil
 Modulus                                       %         Modulo
 Fakultat                                      !        Nachkommastellen des Arguments
                                                         werden ignoriert
 Trigonometrische Funktionen
 Sinus                                         sin       Argumente in Radiant
 Cosinus                                       cos
 Tangens                                      tan
 Arcussinus                                  arcsin      Umkehrfunktionen
 Arcuscosinus                                arccos
 Arucstangens                                arctan
 Exponentialfunktion u. verwandte F.
 Exponentialfunktion                          exp
 Log                                          log        Logarithmus zur Basis 10
 Ln                                            ln        Logarithmus naturalis
 Ld                                            ld        Logarithmus zur Basis 2
 Potenzfunktion                                ^
 Quadratwurzel                                sqrt
 Vergleichsoperatoren
 Groer als                                   >         liefern 0 oder 1
 Kleiner als                                   <
 Kl. gleich                                   =
 Gleich                                       ==
 Und                                          and        Bitweises Und (nur ganze Zahlen)
 Oder                                          or        Bitweises Oder
 Zuweisung                                     =         Erzeugt den Alias:
                                                         Argument1 = Argument2
 Stapelmanipulation
 Pop                                           pop       Oberstes Stapelelement verwerfen
 Tauschen                                     swap       die zwei obersten
                                                         Stapelelemente tauschen
 Duplizieren                                  dup        dupliziert das oberste Stapelelement
 Strings
 Aliasde nition                               "..."

                                       4
Erganzungen:
    Der Zuweisungsoperator benotigt als zweites Argument einen String oder
einen vollstandigen Ausdruck. Die beiden Moglichkeiten unterscheiden sich in
der Auswertung: Wird ein vollstandiger Ausdruck als zweiter Parameter verwen-
det, so wird das zweite Argument sofort ausgewertet, bei einem String ndet
zunachst keine Auswertung statt.
    Strings werden von der Bibliothek gesondert behandelt und muessen zwi-
schen doppelten Anfuhrungszeichen eingegeben werden. Strings und durfen nicht
ineinander verschachtelt werden. Sie dienen der Zuweisung von Aliasen mit dem
Zuweisungsoperator.
    Zusatzlich zu den Funktionen, die Zahlen miteinander verknupfen gibt es
noch ein if Konstrukt fur bedingte Berechnung:
      if
       3 Argumente: Argument 1 wird berechnet und bei Ergebnis ungleich 0
       wird Argument 2 ausgewertet, ansonsten Argument 3.
   All diese Funktionen benotigen fur jeden Parameter jeweils einen vollstandi-
gen Ausdruck.

1.4 Features des UPN Taschenrechners
Der Rechner soll alle Funktionen der Bibliothek verwenden und dem Benutzer
zuganglich machen. Der Rechner stellt auch noch Funktionen zur Verfugung,
die uber die verwendete UPN-Bibliothek hinausgehen:

1.4.1 Serialisierung des Stapels und der Metadaten
Unmittelbar vor Beendigung des Rechners, oder explizit auf einen Befehl des
Benutzers wird der aktuelle Zustand des gesamten Rechners in eine Datei ge-
speichert.
    Das inkludiert den gesamten Stapel sowie benutzerde nierte Variablen und
Aliase, aber auch die Einstellungen der gra schen Benutzerober ache.
    Der Zustand wird beim Neustart des Rechners wiederhergestellt. Der Benut-
zer kann auch wahrend der Arbeit mit dem Rechner den kompletten Rechner-
zustand aus einer Datei importieren. Die serialisierten Daten werden im XML
Format gespeichert.

1.4.2 Die gra sche Benutzerober ache
Das zentrale Element der gra schen Benutzerober ache (GUI) des Rechners ist
ein Eingabefeld, welches den aktuellen Stapel anzeigt. Darin kann mit der Maus
oder Tastatur ein Element markiert werden.
    Im Hauptfenster unter dem Eingabefeld gibt es eine Toolbar welche Knopfe
bietet, die folgende Operationen ausfuhren:
      Das Alias-, das Ausgabe- oder das Eingabefenster o nen.

                                        5
   Loschen: Entfernt den markierten Stapeleintrag
      Pfeil nach oben: Verschiebt den markierten Eintrag nach oben
      Pfeil nach unten: Verschiebt den markierten Eintrag nach unten
      Ansicht andern
       Beim Klick auf dieses Symbol klappt ein Menu auf, mit dem man die
       Notation dieses Ausdrucks andern kann. Es gibt die Alternativen
         1.   Pre x
         2.   In x
         3.   Post x
         4.   Resultat
       Diese Option soll es vor allem Anfangern erlauben in der bekannteren In-
        xnotation die Ausdrucke zu untersuchen. Standard ist hier die Resultat-
       Notation, wobei immer nur das berechnete Ergebnis fur ein Stapelelement
       dargestellt wird. Wenn dieses nicht vollstandig berechnet werden konnte,
       wird der Ausdruck bei dieser Einstellung in Post xnotation dargestellt.
    Die unterste Zeile im Eingabefeld enthalt einen Kommandoprompt, wo man
den nachsten Befehl eingeben kann.
    Optional wird rechts neben dem Hauptfenster ein ein- und ausklappbares
Tastenfeld dargestellt, welches die eingebauten Funktionen zur Verfugung stellt,
damit der Benutzer diese nicht immer auswendig kennen muss. Diese Tasten er-
lauben auch Eingaben mit der Maus, ansonsten geschehen diese uber die Tasta-
tur. In der Toolbar des Hauptfensters gibt es zusatzlich einen Knopf, welcher den
Eingabemodus festlegt. Ist dieser Knopf nicht gedruckt, so wird beim Drucken
einer Operatortaste, die Operation sofort angestossen, anstatt den Operator
einfach in die Eingabezeile zu schreiben.
    Be ndet sich in der aktuellen Eingabezeile jedoch ein o" nendes doppel-
tes Anfuhrungszeichen ohne schlieendes Pendant, so ist nur die herkommliche
verzogerte Ausfuhrung von Operatoren moglich (der Benutzer gibt gerade einen
String bzw. Alias ein - eine sofortige Ausfuhrung bei Operatoreingabe ist hier
nicht erwunscht).
    Links neben dem Eingabefeld gibt es ein ausblendbares Tabellenfenster, wo
in zwei Spalten alle de nierten Aliase und Variablen mit Name und aktuellem
Wert aufgefuhrt werden. Dort kann man auch einen vorhandenen Alias loschen.
    Unter dem Hauptfenster, ebenfalls ausklappbar, gibt es das Ausgabefenster,
in dem die Fehlermeldungen der Bibliothek dargestellt werden.
    Das Kontextmenu auf dem Eingabefeld bietet mehrere Wahlmoglichkeiten:
      Optionen
       siehe unten.

                                        6
   Kopieren
       kopiert das aktuell markierte Stapelelement in die Zwischenablage
      Einfugen
       fugt Text aus der Zwischenablage an der Cursorposition ein.
      Import, Export
       Diese zwei Befehle fuhren jeweils zu einem Dateidialog, und dienen dem
       Import bzw. Export des Rechnerzustandes.
      Exit
       beendet die Anwendung
Auf den Tabs des Optionendialogs stehen dem Benutzer folgende Moglichkeiten
zur Kon guration zur Verfugung:
      Tastaturbelegung andern
       Hier lassen sich die Tastenkurzel fur die wichtigsten Befehle des Rechners
       anpassen.
      Schrift- und Farbauswahl
       Hier kann man sowohl die Schriftart, die Schriftgroe, als auch die Schrift-
       farbe festlegen. Fur den Hintergrund des Eingabefeldes kann man sich
       entscheiden zwischen einem Hintergrundbild oder einer Einzelfarbe.
      Auswahl des numerischen Datentyps und Ersetzungslimit
       In der Basisaustattung kann man hier zwischen double und arbitrary pre-
       cision wahlen Auf dieser Tab kann man auch die Rechengenauigkeit fest-
       legen. Dafur lat sich eine ganze Zahl einstellen. Je hoher dieser Wert
       desto mehr Nachkommastellen werden berechnet. Ist double\ als Daten-
                                                              "
       typ gewahlt, dann bleibt diese Wahl ohne Auswirkung auf Berechungen,
       die Ergebnisse werden jedoch mit der gewahlten Genauigkeit dargestellt.
       Genauso wie die Rechengenauigkeit lat sich fur das Ersetzungslimit ein
       Wert einstellen, welcher begrenzt, wie viele Aliase wahrend einer Stapel-
       auswertung durch ihre De nition ersetzt werden, bevor ein Fehler auftritt
       und die Auswertung abgebrochen wird.

1.5 Bedienung des UPN-Rechners
UPN (bzw. RPN) steht fur umgekehrte polnische Notation (reversed polish no-
tation). In dieser Notation werden mathematische Ausdrucke formuliert, indem
zuerst die Operanden und dann die Operatoren angefuhrt werden. Diese Me-
thode bezeichnet man auch als Post xnotation. Taschenrechner, die mit diesem
Konzept arbeiten, besitzen keine Ist gleich\-Taste. Stattdessen gibt es eine En-
                                 "                                          "
ter\-Taste. Die Funktionsweise des zu programmierenden Rechners soll sich grob
an den von HP erhatlichen UPN-Taschenrechnern (siehe [HP31]) orientieren.

                                         7
Abbildung 1: Stapelabarbeitung

    Die Bedienung funktioniert folgendermaen:
    Operanden und Operatoren werden in der Reihenfolge ihrer Eingabe auf
einen Stapel geworfen.
    Operanden konnen entweder einzeln, d.h. gefolgt von Enter\, oder gleich
                                                          "
mehrere auf einmal, in diesem Fall getrennt durch Leerzeichen, eingegeben wer-
den.
    Operatoren gibt man auf den Stack, indem die entsprechende Taste auf dem
Rechner gedruckt wird, ein Enter\ ist hier nicht notwendig. Da diese Form
                             "
der Eingabe nicht sehr exibel ist, soll es daher in unserer Implementierung
auch optional moglich sein, Operatoren genau wie Operanden handzuhaben,
also mehrere auf einmal einzugeben, ohne dass gleich ausgewertet wird.
    Der Rechner berechnet das Ergebnis, indem er zuerst den Operator und
dann die dazugehorigen Operanden wieder vom Stapel nimmt, die Operanden
mit dem Operator verknupft und das Ergebnis wieder zuruck auf den Stapel
gibt.

1.5.1 Bedienungsbeispiele
Use-Case Beispiele mit schematischer Darstellung zur Erklarung der beschrie-
benen Features. Der Text im schwarzen Kasten zeigt jeweils den aktuellen Stack
des Rechners und die Eingabe des Benutzers hinter dem Prompt.
  1. Berechungen mit Grundfunktionen
     Ausgangsituation:

                                      8
Abbildung 2: Use-cases

   2:23
   1:34
   > + 12 32 - *
  Ergebnis:

    1: -1140
    >
2. Aliasde nition

    1: -1140
    > ZumQuadrat "2 ^" =

    1: -1140
    >
3. Verwendung einer Aliasde nition

    1: -1140
    > ZumQuadrat 3 /

    1: 433200
    >

                                     9
4. Berechnung mit Bedingung
     Folgende Funktion soll realisiert werden:

       function(a) {
         if( a < b ) {
         return a + b;
         else return a * b;
       }

       Eine mogliche Umformulierung auf die UPN Syntax ergibt sich zu:

        > function "c swap = c b < c b + c b * if" =

        >b3=

        1: b 3 =
        > 4 function

        3: 3
        2: 4
        1: 12
        >

1.6 Fehlerbehandlung im Rechner
Wenn bei der Ausdrucksauswertung einer der folgenden Fehler auftritt, so wird
im Ausgabefenster eine entsprechende Fehlermeldung ausgegeben und die Aus-
wertung abgebrochen.
      Syntaxfehler:
       Die Eingabe konnte nicht geparst werden, da sie fehlerhaft war. Mogliche
       Grunde sind:
         { Die Eingabe enthalt mindestens ein ungultiges Zeichen. Erlaubte Zei-
           chen sind Buchstaben des englischen Alphabetes, alle Zi ern von 0
           bis 9 und "." bzw ",", welche beide als Komma interpretiert werden,
           sowie die Zeichen der eingebauten Operatoren.
         { Die Eingabe enthalt eine ungerade Anzahl an doppelten Anfuhrungs-
           zeichen.
         { Eine Zahl oder ein Bezeichner ist nicht syntaktisch korrekt.

                                       10
   Leerer Stapel im Laufe eine Berechnung
       Es wurde ein Ausdruck eingegeben, der zu viele Operatoren enthielt um
       ausgewertet werden zu konnen.
      Fehler wahrend einer Funktionsauswertung
         { Division durch Null
         { Over- bzw. Under ow: Ein entstandenes Ergebnis ist zu gro fur den
           Datentyp mit dem gerade gerechnet wird.
         { Die linke Seite einer Zuweisung war eine Zahl oder der Name einer
           eingebauten Funktion.
      Zu wenig Speicher wahrend einer Berechung

  
2 Uberlegungen zur Losung der Teilprobleme
2.1 Berechnung von Post xausdrucken
Ein Post xausdruck ist nicht anderes, als eine Kette bestehend aus einzelnen
Elementen, welche entweder Operanden oder Operatoren sind. (auf Aliase wird
eingegangen in 2.1.5) Um einen solchen Ausdruck auszuwerten, verwendet man
im einfachsten Fall einen Stapel.
    Die Elemente des Ausdrucks werden der Reihenfolge nach auf den Stapel
gelegt. Danach wird letzterer abgearbeitet.

2.1.1 Stapelabarbeitung
Folgender Algorithmus im Pseudecode arbeitet einen gegebenen Stapel (s) ab
und berechnet ein numerisches Resultat (result):
result eval(stack s) {
  if( s.empty() ) {
    error(); // Fehler: Zu ein Operator hat zu wenig Operanden
  }
  if ( isoperand (s.top()) ) {
    res = s.pop();
    return res;
  }
  else {
    operator = s.pop();
    nrop = nroperands(operator);
    operand[nrop] ;
    for (i = 0..nrop-1) {
      operand[i] = eval(s);
    }
    return operator(operand);

                                      11
}
}

    Dieser rekursive Algorithmus betrachtet die Operatoren als eine Funktion
ihrer Operanden.

                Resultat = Operator(Operand1; Operand2; :::)                 (1)
    Die Funktionen konnen prinzipiell beliebig viele Argumente haben. Obwohl
die meisten arithmetischen Funktionen mit 2 oder weniger Parametern realisier-
bar sind, stot das Konzept schnell an seine Grenzen, wenn man zum Beispiel
einen if Befehl oder Schleifenkonstrukte einfuhren mochte. Zahlen kann man als
konstante Funktionen au assen, die kein Argument haben.

2.1.2 Baumdarstellung eines Post xausdrucks
Der Rechner soll es erlauben, die eingegeben Ausdrucke in Pre x-, In x- und
Post xnotation darzustellen. Um diese Konvertierung durchzufuhren, ist es sinn-
voll, statt einer achen Datenstruktur (Queue oder Liste) einen n-naren Baum
zu verwenden.
    Die Knoten dieses Baumes sind Operatoren und die Blatter sind die Ope-
randen. Ein vollstandiger Post xausdruck zeichnet sich dadurch aus, dass der
entsprechende Baum vollstandig befullt ist, d.h. jeder Operator hat entspre-
chend viele Operanden.
    Im Gegensatz dazu fehlen im Baum zu einem unvollstandigen Ausdruck noch
Knoten, er ist also noch nicht vollstandig auswertbar.
    Mochte man den Baum von der Wurzel her aufbauen, so kann man den
Post xausdruck von hinten nach vorne verarbeitet werden:
    1. Setze das aktuelle Element im Ausdruck an den aktuellen Knoten im
       Baum. Ist es ein Operand dann fertig.
    2. Fur alle Kinder des aktuellen Knotens von rechts nach links: Hole das
       nachste Element, setze den aktuellen Knoten auf das aktuelle Kind und
       fahre rekursiv bei 1. fort.
    Unsere Implementierung geht einen leicht anderen Weg. Die Operanden und
Operatoren werden in der Reihenfolge, in der sie im Ausdruck vorkommen, in
den Baum eingefugt. So muss nicht der Umweg uber eine Liste gegangen werden
und man kommt mit einer Datenstruktur aus.
    Bei unserem Verfahren ist der Wurzelknoten von Anfang an vorhanden. Ein
neuer Knoten wird als rechtester Sohn der Wurzel eingefugt. Danach werden
seine Operanden bereitgestellt, indem die Ausdrucke auf der preceding Achse des
eingefugten Knotens so weit wie notig bzw. moglich nach rechts nachrutschen.

                                      12
Abbildung 3: Post xausdruck in einen Baum umgewandelt

    Bei dieser Art der Befullung kann immer nur ein Teilbaum (Sohn der Wurzel)
unvollstandig sein, und zwar jener der am weitesten links ist.
    Bei der Implementierung wurden zwei verschiedene Realisierungen des Bau-
mes in Betracht gezogen.
    Unter Verwendung der ersten Variante erwies sich die fehlerlose Implemen-
tierung der benotigten Algorithmen als zu schwierig.

   Deshalb wurde danach wieder der klassische Weg eingeschlagen, wobei hier
jeder Knoten eine ArrayList fur seine Kinder verwendet.

                                      13
2.1.3 Umwandlung der Notation
Hat man erst den Baum zu einem Ausdruck erzeugt, kann jede Notations-
art durch eine Traversierungsart erzeugt werden, wobei die In xnotation noch
zusatzlich Probleme aufwirft, da hier, je nach Operatorprioritat, Klammern ge-
setzt werden mussen, und manche Operatoren bestimmte Schreibweisen erfor-
dern. Beispiele sind etwa sin(x) oder x!.
    Wie die Namensgebung schon ausdruckt, erzeugt die pre order-Traversierung
des Baumes Preorderausdrucke, die in order-Traversierung In x- und die post
order-Traversierung Post xausdrucke.
    Da es sich bei den von uns behandelten Baumen nicht um reine Binarbaume
handelt (ein Knoten hat also n-Sohne), mussen die Traversierungskonzepte ein
wenig anpgepat werden:
      Pre- und post order:
       Es werden alle Sohne von links nach rechts rekursiv und danach die Wurzel
       besucht, oder umgekehrt.
      In order:
       Die Sohne werden von links nach rechts besucht. Nach jedem Besuch eines
       Sohnes wird wieder die Wurzel besucht.
    Um das Problem der In xnotation zu losen, wird fur jeden Operator ei-
ne Prioritat festgelegt. Zusatzlich wird noch eine Maske verwendet, um die
Schreibweise festzulegen. Eine Maske ist ein String, der fur jeden Parameter
einen Platzhalter enthalt. Der Platzhalter besteht aus geschweiften Klammern,
zwischen denen die Argumentnummer steht. Diese Syntax wurde gewahlt, da
in C# strings auf diese Art formatiert werden. Man beachte, dass nun normale
geschwungene Klammern verdoppelt werden mussen. Beispiele:
    "f0g!" fur die Fakultatsfunktion
    "if(f0g) fff1ggg else fff2ggg" fur ein if Konstrukt
   Weiters wird zu jedem Operatorargument mit einem boolschen Flag festge-
halten, ob dieses Argumente in irgendeiner Form einklammert ist, wie etwa in
sin(x).

                                       14
Dieses Flag soll uberschussige Klammern verhindern, sodass nicht etwa Er-
gebnisse wie sin((x)) entstehen.
   Bei der in order-Traversierung wird nun beim Besuch eines Knotens des-
sen Maske mit Strings befullt, die von den Sohnen stammen. Das entstandene
Ergebnis wird noch geklammert, wenn alle der folgenden Bedingungen gelten:
  1. Der Vaterknoten hat einen Operator mit hoherer Prioritat.
  2. Das Klammer ag des Vaterknotens ist 0.
  3. Der aktuelle Knoten ist nicht der Wurzelknoten (des Ausdrucks)

2.1.4 Baumauswertung
Die Auswertung beginnt beim Wurzelknoten, welcher seine Sohne von links nach
rechts auswertet. Die Auswertung p anzt sich rekursiv nach unten bis zu den
Blattern vor. Jeder Operator besitzt eine eigene Knotenart, welche ein bestimm-
tes Verhalten besitzt. Bei den Blattern angekommen kann man entweder Ali-
asknoten oder Zahlknoten vor nden. Funktionenknoten, welche nur Zahlknoten
als Sohne haben berechnen ihr Ergebnis und geben es nach oben weiter. Tri t
man im Baum auf einen Aliasknoten, so wird nach einer De nition fur diesen
gesucht. Die De nition ist widerum ein Baum, dessen Wurzel ein quote-Knoten
oder irgendein anderer Knoten sein kann.
    Bei einem quote-Knoten werden all dessen Sohne beim Vater des Aliasknoten
eingesetzt und der Aliasknoten entfernt.
    Da nach diesem Einsetzen der Vaterknoten moglicherweise zu viele Sohne
hat, muss der Baum neu organisiert werden.
    Dazu wird der Vaterknoten zunachst rekursiv gefullt. Das heit, dass alle
seine Sohne genugend Operanden erhalten.
    Danach werden die uberschussigen Knoten des Vaterknotens entlang der
preceding Achse weitergereicht und derselbe Vorgang beim preceding Knoten
nocheinmal durchgefuhrt.
    Handelt es sich um einen einfachen Alias, also ohne quote-Knoten, fallt die
Reorganisierung nach dem Fullen weg.
    Existiert keine De nition fur den Aliasknoten, so ist der Ausdruck nicht
vollstandig, und die Berechnung geht weiter oben weiter.
    Nach dem Ersetzen eines Aliasknotens muss die Berechnung wieder bei der
Wurzel fortsetzen, bzw. bei ihrem Sohn, welcher am weitesten links ist, da sich
die Struktur des Baumes verandert hat und mehr Information vorhanden ist.
Auch das Rekursionslimit ist nun zu beachten.
    Die anderen Knoten werden wie folgt verarbeitet:
  1. Funktionen die eine Zahl als Ergebnis liefern

                                      15
Abbildung 4: Aliasbehandlung: Einsetzen und Reorganisieren

  Die Auswertung ist unproblematisch wie in der Abbildung zur Ergeb-
  nispropagierung ersichtlich.
2. Die Zuweisungsfunktion
   Bei ihrer Auswertung wird nur der rechte Teilbaum ausgewertet und als
   De nition unter dem Namen des linken Sohnknotens gespeichert. Auf Ali-
   ase wird noch tiefer in 2.1.5 eingegangen.

3. Auswertung von Bedingungen und Schleifen

                                  16
Ursprunglich war gedacht, dass die UPN Bibliothek auch Schleifenkon-
  strukte wie for und while kennt.
  Aufgrund der zahlreichen Fallstricke dieser Befehle wurden sie schlielich
  doch nicht implementiert:
        Da es keine Moglichkeit gibt zu erkennen, ob eine Endlosschleife vor-
         liegt, mute die Bibliothek Multithreading verwenden und der Be-
         nutzer Berechnungen von Hand abbrechen.
        For und while Schleifen verkomplizieren die Auswertung enorm und
         lassen sich nicht elegant mit den Aliasde nitionen unter einen Hut
         bringen, da letztere nicht immer nur einen einzigen Ausdruck dar-
         stellen konnen, sondern beliebig viele.
         Ein for Knoten wurde folgendermaen aussehen:

  Relativ einfach verhalt sich die if-Bedingung, weshalb sie auch implemen-
  tiert wurde.
  Sie berechnet zunachst den Wert des Bedingungsknotens, und bei Ergebnis
  ungleich 0 den then-Knoten, sonst den else-Knoten. Konnte die Bedingung
  berechnet werden, ergibt sich als Ergebnis fur den if-Knoten das Ergebnis
  des jeweils genommenen Ausdrucks.

4. Stapelmanipulationsfunktionen
   Im Detail werden die Operationen wie folgt behandelt:
        Pop
         Beim Erzeugen des Baumes wird diese Funktion behandelt, als hatte
         sie ein Argument.
         Bei der Auswertung verschwindet der pop-Knoten inklusive dem Teil-
         baum darunter. Danach wird der Vaterknoten reorganisiert, wie bei
         einem Aliasknoten.

                                     17
Abbildung 5: Alternative Abarbeitung eines swap-Knotens

            Das entstandene Loch wird soweit es geht nach "links verschoben"
            bis es verschwindet, oder ein Fehler auftritt (zu wenig Operanden).
           Swap
            Swap wird bei der Baumerzeugung als Funktion mit 2 Argumenten
            betrachtet.
            Bei der Auswertung werden die 2 Subbaume in umgekehrter Reihen-
            folge beim Vaterknoten eingefugt und dieser reorganisiert. Alternativ
            kann man den swap Knoten auch als Funktion ohne Argument anse-
            hen. Die Abarbeitung wurde dann wie in der Abbildung geschehen.
           Dup
            Dup hat wie Pop genau ein Argument. Hier wird bei der Auswertung
            der Argumentbaum geklont (eine tiefe Kopie wird angelegt). Beide
            Baume werden beim Vaterknoten eingefugt und letzterer muss neu
            organisiert werden.

2.1.5 De nition und Auswertung von Aliasen
Ein Alias ist auch nichts anderes als ein Post x Ausdruck, also eine Folge von
Operanden (konnen u. a. auch Aliase sein) und Operatoren.
   Da die Schachtelungstiefe der Aliase zur Laufzeit nicht bekannt ist, geschieht
das Ersetzen so oft, wie es notig ist. Dieser Vorgang wird durch ein, vom Be-
nutzer gewahltes, Rekursionslimit begrenzt.
   Wird das Limit uberschritten, so wird die Auswertung abgebrochen und die
Bibliothek meldet einen Fehler, welchen die GUI im Ausgabefenster als "uber-
schrittenes Rekursionslimit" darstellt.
                   
   Um bei einem Uberlauf   nicht alle Daten zu verlieren, wird der gesamte Baum
                                           
vor jeder Auswertung geklont. Tritt kein Uberlauf    oder sonstiger Fehler auf, so
wird das Ergebnis ubernommen, ansonsten wird der vorher geklonte Ausdruck
wiederhergestellt.
                                 >A "2 B +" =
                                 >B "3 A" * =
                                 >A

                                        18
Die Abbildung zeigt zwei De nitionen und ein Anweisung. Letztere uber-
schreitet bei der Auswertung jedes Rekursionslimit.
    Da Aliasde nitionen in doppelten Anfuhrungszeichen stehen, kann man bei
der Baumerzeugung das erste Anfuhrungszeichen als einen Operator interpre-
tieren, welcher beliebig viele Operanden besitzt.
    Alle auf das erste Anfuhrungszeichen folgenden Elemente des Post xaus-
drucks werden deshalb unterhalb des quote-Knotens nach dem bereits bekann-
ten Schema eingefugt.
    Folgt schlielich das schlieende Anfuhrungszeichen, wird wie vor dem ersten
Anfuhrungszeichen fortgesetzt.
    Tri t man bei der Baumauswertung auf einen quote-Knoten, so werden seine
Kinder einfach nicht berechnet.
    Ein solcher Knoten kommt nur als rechter Sohn eines Zuweisungsknoten zum
Tragen.
    Eine Hashtabelle verwaltet alle Aliase. Der Aliasname wird als key gespei-
chert. Value ist jeweils der rechte Teilbaum des ausgeschnittenen Baumes, dessen
Wurzel der quote-Knoten ist.

2.2 Arithmetik mit beliebig groen Zahlen
Die meisten Computer arbeiten wortorientiert und will man mit Zahlen rechnen
die groer sind als ein Maschinenwort (abgesehen von speziellen Gleitkommaty-
pen) muss man auf kompliziertere Verfahren in Software zuruckgreifen, welche
auf den Wortoperationen in der Hardware aufbauen.
    Das Gebiet ist gut erforscht und es gibt viele Implementierungen. Auch im
.NET Framework 1.1 wird bereits eine Bibliothek (vjslib.dll) mit ausgeliefert,
wenn auch ein wenig versteckt [MSDN]. Diese Bibliothek deckt aber nicht ganz
den Bedarf fur die UPN-Bibliothek ab, weswegen in diesem Projekt eine eigene
Klasse dafur entwickelt wurde.

2.2.1 Reprasentation
Eine gangige Art der Reprasentation von beliebig groer Zahlen ist ein Stellen-
system, wie wir es vom Dezimalsystem kennen. Um die Berechnung ezienter
zu gestalten wahlt man am besten eine sehr groe Basis. Obwohl sich zur ge-
                      
genwartigen Zeit ein Ubergang  zu 64-bit Rechnern vollzieht, aber die meisten
Rechner noch 32 Bit Wortbreite haben lag es nahe in der Bibliothek 232 als
Basis fur die Implementierung zu wahlen.

2.2.2 Basenkonvertierung
Die Basenkonvertierung ist ein wichtiges Problem, welches zuerst gelost werden
muss, um fur den Menschen gewohnte Zahlen zu erzeugen. Fur die Ein- und
Ausgabe von Zahlen muss sowohl eine Umwandlung vom Dezimalsystem weg,
als auch eine Ruckkonvertierung implementiert werden.

                                       19
Um eine ganze Zahlen in unsere nun viel groere Basis umzuwandeln, durch-
wandert man ihre Dezimalzi ern von rechts nach links, und summiert je eine
Zi er auf das Ergebnis auf, und solange es noch Zi ern gibt multipliziert man
die Zahl danach mit 10.
    Zur Ruckumwandlung ins Dezimalsystem dividiert man die Zahl wiederholt
durch 10 und schreibt jeweils den Rest an.

2.2.3 Grundrechenarten
Um rechnen zu konnen muss man zuerst die primitiven Operationen realisieren:
    Sind erst einmal die Grundrechenarten gelost, so kann man eigentlich auch
alle anderen mathematischen Funktionen auf diesem Fundament aufbauen.
    Die einzelnen Grundrechenarten lassen sich wie folgt implementieren:
      Addition
       Bildlich erklart erfolgt die Addition durch ubereinanderschreiben der bei-
       den Zahlen, wobei jeweils gleichwertige Stellen ubereinander stehen.
       Man beginnt bei der niederwertigsten Stelle und addiert je zwei Zi ern,
       bis die Zahl mit weniger Stellen ihr Ende erreicht, wonach die restlichen
       Zi ern der anderen Zahl ohne Rechnung einfach angeschrieben werden
       konnen.
       Bei der Addition von zwei Zi ern (bei uns ein Maschinenwort) muss jeweils
           
       ein Ubertrag   beachtet werden der entweder 0 oder 1 ist.
                                                                             
       Da heute eigentlich keine Hochsprachen mehr direkt Zugang auf den Uber-
       lauf bietet, muss man sich z.B. in C# mit einem checked-Statement be-
       helfen, oder man rechnet mit 64 bit unsigned integers und extrahiert
            
       den Ubertrag    mit einem bitweisen Oder. In der Literatur ndet sich kein
       schnelleres Verfahren, als jenes, das vorher beschrieben wurde.
      Subtraktion
       Bei der Subtraktion geht man ahnlich vor wie bei der Addition. Statt einer
       add-with-carry benotigt man eine sub-with-borrow Operation.
       Auch diese liegt in C# nicht vor muss also eher holprig implementiert
       werden, will man nicht auf native Funktionen aufbauen. Wieder gilt es,
       Exceptions zu vermeiden, und stattdessen mit low level Operationen wie
       bei der Addition zu verfahren.
      Multiplikation
       Die Multiplikation lat sich auf verschiedenste Arten implementieren. In
       diesem Projekt wird die einfachste, robusteste und fur Groenordnungen
       des taglichen Gebrauchs auch ezienteste Variante verwendet. Dieses Ver-
       fahren wird in der Literatur zumeist als Schulbuchverfahren bezeichnet
       (school book method). Die Laufzeitkomplexitat betragt O(n2 ) fur zwei
       Zahlen mit je n Worten.

                                        20
Das Verfahren iteriert uber die Zi ern eines Multiplikanden. Der zweite
       Multiplikand wird jeweils mit einer Zi er multipliziert, und das Ergebnis,
       solange noch Zi ern kommen, um eine Zi er nach rechts geshiftet.
       Aus der Literatur sind vor allem noch die Fast Fourier Multiplikation
       sowie das Verfahren von Karatsuba erwahnenswert. Beide sind ein we-
       nig schwieriger zu implementieren bzw. zu testen. Belohnt wird man erst
       bei Stellenzahlen wie man sie beispielsweise fur kryptopgra sche Zwecke
       benotigt. ( (vgl. [Gathen99])
      Division
       Sie ist die anspruchsvollste aller Grundrechenarten. Hier wurde von mir
       Knuth's Algorithmus [Knuth2] als Grundlage verwendet.
       Der Algorithmus berechnet ahnlich wie beim Rechnen von Hand das Er-
       gebnis beginnend mit der hochstwertigen Stelle. Jede Ergebniszi er wird
       zuerst geschatzt (bei Knuth: q^), in dem man die ersten zwei Stellen des
       jeweils verbleibenden Rests durch die erste Stelle des Divisors dividiert.
       Dann wird q^ mit dem Divisor multipliziert und vom Rest abgezogen. Ist
       das Ergebnis negativ so muss man q-Dach um 1 reduzieren und wieder
       multiplizieren und subtrahieren solange bis der Rest >= 0 ist.
       Man beachte dass q^ nur ein guter Schatzwert ist, wenn die erste Zi er des
       Divisors groer als die Halfte der verwendeten Basis ist. Ist das nicht der
       Fall benotigt die Division zuviel Zeit da q^ viel zu gro gewahlt wird.
       Knuth zeigt, dass
       q^ hochstens um 2 zu gro ist () die erste Zi er des Divisors > b Basis 2
                                                                                    c.
       Multipliziert man beide Zahlen mit b erste Ziffer des Divisors c, was nur einer
                                                       Basis
       Multiplikation mit einer Zi er bedeutet, so kann man sicherstellen, dass
       die erste Zi er des Divisors gro genug ist.
       Knuth's Algorithmus berechnet keine Nachkommastellen, weshalb er er-
       weitert wurde. Unser Algorithmus berechnet ein vorgegebene Anzahl an
       Nachkommastellen. Sobald der aktuelle Rest kleiner wird als der Divisor,
       be nden wir uns hinter dem Radixpunkt und der Rest wird nach jeder
       berechneten Stelle um 32 Bit nach links geshiftet.
       Diese Art der Division ist bis auf sehr groe Zahlen vernunftig schnell. Bei
       extrem groen Zahlen lohnt es sich daher einen andere Wege zu gehen, etwa
       zuerst das Inverse des Divisors zu berechnen und anschlieend eine schnelle
       Multiplikation durchzufuhren, oder das Newtonverfahren zu verwenden.

2.2.4 Hohere Funktionen
Die nun folgenden Operationen werden zumeist durch Naherungen aus der Ana-
lysis auf der Basis von Potenzreihen berechnet. Genauere Ausfuhrungen nden
sich unter anderem in [Konigsberger90]. Die Verwendung von Potenzreihen ist
zumeist sehr langsam, da sehr groe Zwischenergebnisse entstehen.

                                          21
   Modulo
    Die Division in obiger Form liefert gratis den Rest wenn man einfach zu
    dividieren aufhort sobald der Radixpunkt erreicht ist.
   Exponentialfunktion
    Sie lat sich am einfachsten berechnen, indem man Sir Isaac Newton's
    beruhmte Formel verwendet, welche eine gute Konvergenz hat.

                           exp(x) =
                                      X1  xn
                                             f ur x 2 R                    (2)
                                      n=0 n!
    Fur die Genauigkeit gelten die bekannten Abschatzungen.
   Potenzieren
    Handelt es sich um einen ganzzahligen Exponenten kann diese Rechenart
    auf wiederholte Multiplikation zurckgefuhrt werden.
    Ist dem nicht so, greift man zuruck auf die De nition der Potenzfunktion
    durch die Exponentialfunktion.
                             x =e     ln   x f ur x 2 R                    (3)
                                                           +

   Logarithmus
    Zur Berechnung kann man folgende Reihe verwenden:

                           ln(1 + x) =
                                           X1 ( 1)  k+1 x
                                                         k
                                                                            (4)
                                           k=1             k

    Da diese nur im Intervall [ 1; 1] konvergiert, ist Identitat notig um auf
    ganz R rechnen zu konnen:

                                    1
                                 ln( ) =         ln(x)                      (5)
                                    x
   Quadratwurzel
    Aus Newton's Verfahren der Nullstellenberechnung kann man folgende
    Rekursionsformel zur Berechnung von Wurzeln gewinnen. Das Verfahren
    konvergiert sehr gut, darf aber nur auf positive Zahlen angewandt werden.
    Sei x0 = 1 und weiters:

                                     1      a
                               xn+1 = (xn + )                               (6)
                                     2     xn
    wobei x1 = a
                 p

                                      22
   GGT
       Groter gemeinsamer Teiler: Eine wesentliche Funktion aller Computeral-
       gebrasysteme. Diese Funktion wird vor allem benotigt, um Bruche zu
       kurzen. Geeignet fur ihre Berechunng ist der sehr bekannte Euklidische
       Divisionsalgorithmus (etwa zu nden in [Knuth1]), welcher sich auch fur
       sehr groe Zahlen eignet.
       Der folgende Pseudocode berechnet ggT(a, b):

       while(b > 0) {
         r = a Mod b
         a = b
         b = r
       }
       ggT = a

      Sinus, Cosinus und Tangens
       Zuerst ist es immer ratsam die Eingabewerte fur diese Funktionen rela-
       tiv klein zu halten, um Prazision und Schnelligkeit zu garantieren. Dies
       geschieht mittels Rechnung mod 2   . Die Implementierung erfolgt der
       Einfachheit halber mit den bekannten Reihen, welche relativ schlecht kon-
       vergieren.

                               sin(x) =
                                        X1 ( 1)  n x
                                                    2n+1
                                                                                  (7)
                                                (2 + 1)!
                                                     n
                                          X1 ( 1)
                                          n=0
                                                      2n
                                 cos( ) =
                                     x             n x                            (8)
                                           n=0       (2n)!
                                                        sin(x)
       Wie allgemein bekannt gilt schlielich: tan(x) = cos(x) . Es sei noch erwahnt,
       dass zahlreich schneller konvergierende Reihen existieren.

2.2.5 Darstellung von Nachkommastellen
Die Darstellung von reellen Zahlen im Computer ist ein eigenes Forschungsge-
biet.
    Das Hauptproblem sind die periodischen Dezimalzahlen, wie sie bei der Di-
vision entstehenpkonnen. Noch schlimmer sind aperiodische, irrationale Ergeb-
nisse, wie etwa 2 oder  .
    Um durch Divisionen nicht an Genauigkeit zu verlieren, kann man, wie in
den meisten bekannten Computer Algebra Systeme verwendet, Zahlen intern
als Bruche darstellen.
    Ein Problem ist die Frage wann Bruche gekurzt werden. Das Kurzen benotigt
viel Rechenzeit, aber vereinfacht Zahler und Nenner nicht in jedem Fall.

                                          23
Abbildung 6: Klassendiagramm auf der Analyseebene

    Funktionen wie Sinus etc. berechnet man immer genauer, indem man mehr
Glieder der Potenzreihe berechnet, oder bei Verwendung von Rekursionsformeln
die Rekursionstiefe erhoht.
    Als Ergebnis erhalt man meist einen Bruch mit riesigem Nenner und Zahler,
was fur eine Maschine keine Rolle spielt. Der Bruch wird erst aufgelost bevor
das Ergebnis in gewohnter Dezimaldarstellung benotigt wird.
    Die Bruchau osung, d.h. die Division, erfolgt jeweils mit der Prazision, die
vom Benutzer der UPN-Bibliothek eingestellt wurde. Der bereits beschriebene
Divisionsalgorithmus muss dazu nur so abgewandelt werden, dass er so viele Er-
gebniszi ern berechnet wie erforderlich. Zusatzlich muss auch noch die Position
des Kommas im Ergebnis gespeichert werden.
    Um das Ergebnis wieder ins Dezimalsystem umzuwandeln, betrachtet man
die Teile vor und hinter dem Komma separat.
    Der vordere Teil wird wie schon beschrieben umgewandelt. Der hintere muss
nun jeweils mit 10 multipliziert werden, um eine Dezimalzi ern zu extrahieren.
Nach dem Multiplizieren wird der ganzzahlige Anteill wieder weggeschnitten
und die nachste Zi er berechnet.
    Da Zahlen, deren Nachkommastellen aus Zehnerpotenzen zusammengesetzt
sind, im Binarsystem eine periodische Darstellung besitzen, ist die Umwand-
lung zuruck zum Dezimalsystem problematisch. Man muss sich mit Rundungen
behelfen, oder wie in unserem Fall diesen Umstand einfach ignorieren.
    Aus einer Eingabe von "1.1" resultiert demnach, je nach eingestellter Prazi-
sion, z.B. die Ausgabe "1.0999". Intern ist jedoch nichts an Genauigkeit verloren
gegangen, da die Ungenauigkeit nur die Ausgabe betri t.

    
2.3 Uberlegungen zur Modularisierung
In der Urspezi kation dieses Projektes und auch in der ersten Implementierung
habe ich mich entschlossen die Bibliothek und den Parser in einer DLL zu verei-
nen, die mit der Auenwelt nur uber Strings kommuniziert. Die GUI wurde auf
dieses Konstrukt aufgesetzt, aber die Komponenten wirkten nicht harmonisch
zusammen.
    Dieser erste Ansatz war o enbar falsch. Eine Verbesserung bringt die strikte
Trennung von Parser, GUI und UPN-Bibliothek, wie in der Abbildung darge-
stellt

                                       24
Abbildung 7: Die UPN-Bibliothek

    Die zweite Abbildung verdeutlicht den Aufbau der UPN-Bibliothek inklusive
                                                               
der wichtigsten beteiligten Hilfsklassen. Zur Steigerung der Ubersichtlichkeit
wurden nicht alle Methoden und Klassen dargestellt: Von der abstrakten Node-
Klasse wird etwa fur jeden Operator, jeden Aliasnamen und jede Konstante
(Zahl) noch eine Klasse abgeleitet, die das jeweilige Verhalten implementiert.
Fur die Details sei auf die Dokumentation verwiesen, siehe 3.

2.4 Austauschbarkeit von Number Klassen
Da die UPN Bibliothek mit abstrakten Zahlen vom Typ Number rechnet, wurde
eine factory class notig, welche zur Laufzeit die Objekte erzeugt. Um nachtragli-
che Erweiterungen zu ermoglichen wurde hier auf die Moglichkeiten zuruckge-
gri en, die die Re ection API von C# bietet. Eine NumberFactory wird uber
einen Verweis auf ein Module (EXE oder DLL) erzeugt und durchsucht dieses
nach Typde nitionen, die von Number abgeleitet sind.

2.5 Parser fur Post xausdrucke
Die EBNF-Grammatik gultiger Eingaben fur unseren UPN-Taschenrechners
fallt eher einfach aus, da auch unvollstandige Ausdrucke akzeptiert werden, weil
erst am Ende bei der Stapelauswertung klar wird, ob die Eingabe einen Sinn
ergibt.

                                        25
Abbildung 8: Der UPN-Parser

    Grammatik der Post xausdrucke
    Eingabe ::= f Teilausdruck j Aliasde nition g.
    Teilausdruck ::= f Zahl j Aliasname j Operatorg.
    Aliasde nition ::= Quote Teilausdruck Quote.
    Aliasname ::= CharfCharg Space.
    Operator ::= ('+' j '-' j '*' j ... j 'for') Space.
    Zahl ::= ['-']Zi er fZi erg [('.'j',') Zi er fZi erg] Space.
    Char ::= 'a' j 'b' j 'c' j ... j 'z' j 'A' j 'B' j ... j 'Z'.
    Zi er ::= '0' j '1' j '2' j '3' j '4' j '5' j '6' j '7' j '8' j '9'.
    Space ::= ' '.
    Quote ::= ' "'.

    Damit der Parser austauschbar bleibt, wird er uber ein Interface namens
Parser realisiert. Applikationen, welche die UPN-Bibliothek verwenden, sind
so nicht nur auf UPN Ausdrucke beschrankt, sondern konnten beispielsweise
einen In xparser implementieren. Die Zahlendarstellung im Parser wurde sehr
einfach gehalten. Auf die Eingabe von Zahlen in Exponentialschreibweise wurde
verzichtet, um Komplexitat zu sparen. Die Ausgabe der GUI wurde nachtraglich
schon um eine Ausgabe in Exponentialschreibweise erweitert, da recht lange
Rechenergebnisse mitunter zuviel Platz am Bildschirm benotigen.

2.6 Aufgaben der GUI
2.6.1 Tastatureingaben verwalten, und verarbeiten
Damit die Benutzerober ache Akzeptanz ndet, muss sie sich den individuellen
Vorlieben ihrer Benutzer anpassen konnen. Fortgeschrittenen Benutzern ist es
vor allem wichtig, dass die Tastaturbelegung sich kon gurieren lat.
   Die UPN GUI de niert fur alle wichtigen Aktionen des Benutzers eine Tas-
te bzw. Tastenkombination. Die Tastenbelegung wird auch im XML Format

                                            26
gespeichert.
    Nicht alle Tasten sind frei kon gurierbar, so bleiben beispielsweise die Zif-
fertasten immer so belegt, wie sie beschriftet sind, was mogliche Verwirrungen
ausschliet.

2.6.2 Automatische Eingabekorrektur
Um dem Benutzer die Eingabe von Ausdrucken zu erleichtern und Fehler dabei
so gut wie moglich zu vermeiden, berucksichtigt die GUI folgende Techniken:
      Die backspace-Taste loscht nicht nur ein Zeichen, sondern einen ganzen
       String, sofern sich links neben dem Cursor nur Buchstaben be nden, also
       keine Zahl eingegeben wurde.
      Folgt auf die Eingabe einer Zahl ein Buchstabe, so wird dazwischen auto-
       matisch das notwendige Space eingefugt. Das passiert auch bei der Eingabe
       von Operatorsymbolen.
      Wahrend der Eingabe einer Zahl (Zi er oder Komma links neben dem
       Cursor), bewirkt das Einfugen eines "-" Zeichens, dass die Zahl ihr Vor-
       zeichen andert. Das Vorzeichen wird also korrekt vor die Zahl gestellt.
      Wurde bereits ein o nendes doppeltes Anfuhrungszeichen eingegeben, so
       wird das Drucken der Enter-Taste ignoriert und die eventuell eingeschal-
       tete "Sofortauswertung bei Operatortaste" auch temporar deaktiviert.
  Realisiert werden diese Funktionen hauptsachlich unter Verwendung der
RPNParser-Klasse.

2.6.3 Ausklappbare Fenster
Die Ezienz bei der Benutzung kann auch gesteigert werden, in dem immer nur
GUI-Elemente auf dem Bildschirm angezeigt werden, die im Moment gerade
benotigt werden. Der Taschenrechner hat etwa nur Tasten auf dem Bildschirm,
wenn das entsprechende Fenster ausgeklappt wurde. Gleiches gilt fur die Aus-
gabe und das Variablenfenster.
   Die klappbaren Fenster des UPN Rechners docken jeweils an einer Seite des
Hauptfensters an, sodass bei einer Bewegung des letzteren alle anderen Fenster
mit verschoben werden.

2.6.4 Benutzung der Zwischenablage
Um Interaktion mit anderen Programmen zu ermoglichen mussen berechnete
Ergebnisse rasch in andere Applikationen ubertragbar sein. Ein Rechtsklick auf
eine Zahl im Rechnerfenster erzeugt ein Kontextmenu welches das Kopieren
dieser Zahl in die Zwischenablage erlaubt. Das Eingabefeld ist auch mit die-
ser Fahigkeit ausgestattet, sodass das Einfugen von Werten (Strings) aus der
Zwischenablage problemlos moglich ist.

                                       27
2.6.5 Popupfenster versus Fenster mit Titelleisten
Lange habe ich die Moglichkeit in Erwagung gezogen, das Rechnerfenster so
zu schreiben, dass keine Fensterleiste sichtbar ist, um Platz am Bildschirm zu
sparen. Moglich ware dann die Bewegung des Fensters, wie auf Unix Systemen
ublich, durch ein gleichzeitiges Drucken der ALT-Taste wahrend dem Ziehen
mit der Maus.
    Unter Windows entspricht dies nicht den empfohlenen Richtlinien fur Appli-
kationen, weshalb in diesem Projekt das Hauptfenster kein Popupfenster ist.

2.6.6 Look and Feel der GUI
Eine optisch gut aussehende Benutzerober ache schmeichelt nicht nur dem Au-
ge, sondern erhoht auch die Usability. Deswegen sind Schriftgroen und Hin-
tergrundfarben des Rechnerfensters frei einstellbar. Genauso verhalt es sich mit
der Fenstergroe:
    unterschiedliche Bildschirmau osungen bewirken ein eher schwaches Ab-
schneiden von Applikationen die ihren Benutzern eine xe Fenstergrose vor-
geben.
    Die Starke von Fenstersystemen liegt eben genau darin, dass der Benutzer
sich seine Fenster so gro machen kann wie er mochte. Jede kunstliche Restrik-
tion durch den Programmierer sollte einwandfrei begrundet sein.

2.7 Zustandsserialisierung mit XML
Da die C#-Klassenbibliothek eine hervorragende Grundlage bietet um XML-
Daten zu verarbeiten, und XML in den letzten Jahren ein wichtiger Industrie-
standard geworden ist, lag es nahe die Serialisierung des Rechnerzustandes in
diesem Format durchzufuhren.
    Der Zustand des UPN-Rechners setzt sich zusammen aus dem Zustand der
UPN-Bibliothek und den aktuell eingestellten Optionen der GUI (inklusive ak-
tuelle Sichtbarkeit der einzelnen Fenster) Zusammengesetzt ergibt sich folgendes
Format, welches hier durch ein Beispiel veranschaulicht wird. Der Stapelinhalt
und die Aliasde nitionen be nden sich in CDATA Sektionen, weshalb sie nach
der Validierung der XML-Datei noch geparst und auf ihre Korrektheit uberpruft
werden mussen:

                                       28
3
    BigDecimal
    100
  
      Arial
      13
      
        0
        0
        12345
      
      12345
    
    1
    1
    1
    1
    5
    
       65
       
  Zur Validierung solcher XML-Dateien wird folgende XSD benutzt:

                                  29
30
Diese Schemade nition ist x als Resource in die ausfuhrbare Datei des
Rechners eingebettet, kann also nicht vom Benutzer verandert werden.

2.8 Testen der Bibliothek und der Arithmetikklassen
Die wichtigsten Testfalle in diesem Projekt sind sicher jene, die die Korrekt-
heit der Operationen auf BigInteger-Objekten sicherstellen. Das Schreiben von
arbitrary precision-Klassen ist keine triviale Programmieraufgabe.
    Ein Rechner, kann er auch mit noch so groen Zahlen rechnen, ist wertlos,
wenn er falsche Ergebnisse liefert. Es leuchtet ein, dass wesentliche Testfalle fur
die Berechnungsklassen nicht leicht zu nden sind. Noch schwieriger und feh-
leranfalliger ist das handische Erzeugen von Ergebnissen. Deshalb habe ich mich
dazu entschlossen das Computeralgebrasystem Mathematica [Wolfram] mit die-
ser Aufgabe zu betrauen. Viele Tests wurden als eigenstandige, lau ahige Klas-
sen geschrieben und decken viele, aber bei weitem nicht alle Spezialfalle bei
Rechenoperationen ab.

3 Dokumentation der Implementierung
Die Dokumentation liegt in Form von HTML-Dokumenten vor und ist in Eng-
lisch verfasst. Sie wurde durch ein Werkzeug automatisch aus dem Quellcode
generiert.

                                         31
4 Kritische Beurteilung
Es handelt sich um eine breite, aber an wenig Stellen tiefgehende Arbeit. Inter-
essant sind vor allem die Baumalgorithmen der UPN Bibliothek und die Eleganz
der UPN selbst.
    Die entstandene UPN Bibliothek ist ein brauchbarer Softwarebaustein, wel-
cher in zahlreichen Applikationen Anwendung nden konnte. Im Bezug auf die
Arithmetikklassen lag das Hauptaugenmerk nicht auf dem Finden und Imple-
mentieren der performantesten Algorithmen, vielmehr wurden leicht verstandli-
che Verfahren implementiert. In den Fallen wo eine bessere Losung bekannt ist,
wurde dies in diesem Text erwahnt.
    Obwohl die Zielplattform am Anfang des Projekts klar auf Windows festge-
legt wurde, lauft die UPN Bibliothek auch unter Mono. Die Rechner GUI wird
auch unter Mono funktionieren, sobald das WinForms Projekt seinen Abschluss
  ndet.

4.1 Vergleich mit vorhandenen Produkten
Stapelrechner und Bibliotheken nden sich sehr zahlreich im Internet. Eine gute

Ubersicht  bietet [TLDP]. Die Implementierungssprachen reichen von JavaScript,
C bis Lisp und der Funktionsumfang variiert dabei erheblich. Ein klarer Favorit
kann nicht ausgemacht werden, und so liegt es im Ermessen des Benutzers, seine
individuelle Entscheidung zu tre en.
    Auf dem Markt existieren zahlreiche arbitrary precision Implementierungen,
aber die meisten davon wurden in C geschrieben. Unserer Implementierung in
diesem Projekt erhebt keinen Anspruch auf vollstandige Korrektheit. Im ur-
sprunglichen Thema war eine solche Implementierung auch nicht gefordert.

4.2 Mogliche Verbesserungen
    Erweiterung um Schleifenbefehle
    Einstellbarer Radix fur die Zahlendarstellungen (ermoglicht Ein- und Aus-
       gabe von Zahlen in anderen Basen: hexadezimal, binar, etc.)
      Unterstutzung fur Listen, Vektoren und Matrizen
      Imaginare Zahlen
      Verbesserung der BigNumber Klasse: Mehr Performanz durch bessere Al-
       gorithmen.

Literatur
[HP31] Webseite des HP31, http://www.hpmuseum.org/hp31.htm (2.5.2006)

                                       32
[TLDP] The Linux documentation project,
    http://www.tldp.org/linuxfocus/Deutsch/January2004/article319.shtml
    (2.5.2006)
[Gathen99] Joachim von zur Gathen und Jurgen Gerhard, Modern Computer
    Algebra, 1999
[Wolfram] Mathematica Computer Algebra System, http://www.wolfram.com
    (2.5.2006)
[Knuth1] Knuth, Donald E., Fundamental Algorithms - Volume 1 of "The Art
    of Computer Programming", Third Edition, 1997
[Knuth2] Knuth, Donald E., Seminumerical Algorithms - Volume 2 of "The Art
    of Computer Programming", Third Edition, 1997
[MSDN] BigInteger-class MSDN,
   http://msdn.microsoft.com/msdnmag/issues/05/12/NETMatters/
   (23.5.2006)
[Konigsberger90] Konigsberger, Analysis 1, 1990

                                      33
Sie können auch lesen