Bakkalaureus der technischen Wissenschaften - Ein UPN-Taschenrechner in C#
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
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