Symbolisches Differenzieren von Termen

Ein Praktikum an der Universität Leipzig.
Praktikant Hannes Schulz
Aufsicht und Anleitung M. Meiler und A. Zerbst
Zeitraum19. bis 25. 2. 2001
Inhaltsverzeichnis
> Aufgabenstellung
> Programmiersprache
> Vorüberlegungen
> Lösung der Aufgabe
> Erweiterungen
> Bemerkungen zum Praktikum

 Aufgabenstellung

Es war ein Programm zu erstellen, welches einen gegebenen vollständig geklammerten Term-String in seine Bestandteile zerlegt, nach den bekannten Regeln differenziert und ausgibt.

INPUT: Vollständig geklammerter Term f
OUTPUT: Ableitung f' von f

< Zurück nach oben



 Programmiersprache

Es wurde in C programmiert.

< Zurück nach oben



 Vorüberlegungen

Beschreibung der Syntax

  • Zwei Terme werden immer mit einem Verknüpfungszeichen verbunden.
  • Zwei Terme mit Verknüpfungszeichen werden in Klammern eingeschlossen.
  • Nach Funktionen (sin, tan etc.) folgt ein Leerzeichen und ein Term. Klammern sind nicht notwendig, es sei denn der Term besteht aus Untertermen.


Um einen Term in "Unterterme" Aufteilen zu können ist es notwendig seinen Anfang und sein Ende bestimmen zu können.

Die Beschriebung von "Term" anhand des Anfangszeichens:

  • 'x' -- Es folgt nichts. Ende des Terms unmittelbar hinter dem 'x'.
  • Zahl -- Es folgt nichts. Ende des Terms nach dem letzten Zahlzeichen.
  • '(' -- Ein Term, welcher aufgeteilt werden muss. Sein Ende befindet sich an der korrespondierenden schließenden Klammer (auszählen). Das Hauptverknüpfungszeichen befindet sich nach dem Ende des ersten Terms in der Klammer.
  • Funktion -- Ein weiterer Term folgt. Ende des gesamten Terms ist das Ende dieses folgenden Terms.


Für die Differenzierung fällt auf, dass die Anwendung der Differentiationsregeln abhängig von den verknüpften Termen ist. So ist z. B. die Verwendung der Kettenregel im folgenden Falle nicht angebracht:

f(x) = (x^3)
f'(x) = (3*(x^2))

 -- wohl aber hier:

f(x) = (x^sin x)
f'(x) = [Programm ausprobieren!!!]

< Zurück nach oben



 Lösen der Aufgabe

Der vollständig geklammerte Term wird aufgegliedert, indem man sein Ende bestimmt. Stimmt dieses mit '\0' überein ist die Bearbeitung abgeschlossen. Sonst werden die äußeren Klammern entfernt und es wird nach den oben aufgeführten Regeln mit der Bearbeitung fortgefahren, bis entweder alle Klammern aufgelöst sind, oder sich ein neues Hauptverknüpfungszeichen findet.
Im ersteren Falle wird die Ableitung des nun auf wenige Fälle begrenzten Terms ermittelt (z. B. x^2 wird zu 2*x), im zweiten Falle wird eine Differentiationsregel angewandt, (z. B. (u)*(v) wird zu (uv') + (u'v)).
Hier werden u' und v' rekursiv ermittelt, indem die Funktion mit u' bzw. v' als Parameter erneut aufgerufen wird.
Anhand des Hauptverknüpfungszeichens und der Art der Teilterme wird also die Art des Verfahrens entschieden und das Ergebnis zusammengestellt. z. B.:

f(x) = ((3+x)*(x^2))
  
  Hauptverknuepfungszeichen = '*'
  Term u = 3+x ; u' = 1
  Term v = x^2 ; v' = 2*x
  Regel: wenn f = u * v dann ist f' = u' v + u v'
  
f'(x) = ((x^2) + ((3+x)*(2*x)))

Mit den evtl. vorhandenen Teiltermen wird durch rekursiven Aufruf genauso verfahren. Ersetzen wir z. B. a = (3+x) mit a = ((3+x)^2), so wird die Ableitung a' durch einen erneuten Aufruf der Funktion gebildet, die wiederum das Hauptverknüpfungszeichen (hier '^') sucht und geeignete Operationen anwendet (Da das Auflösen nach dem Pascalschen Dreieck noch nicht implementiert wurde käme hier die Kettenregel zum Einsatz.).

< Zurück nach oben



 Erweiterungen

Es stellte sich heraus, daß eine Funktion zum Vereinfachen der Gleichungen günstig ist, da die differenzierte Funktion sonst in einem Chaos von Klammern untergeht, welche zwar richtig sein mögen, aber unnötig sind. Die Abgeleitete Funktion wird dadurch übersichtlicher.
Hier wurden wegen des großen Aufwandes nur simple Vereinfachungen realisiert, welche jedoch eine immense Wirkung auf das Ergebnis hatten.

Wichtige Vereinfachungen:

  • Operationen mit 2 gleichen Termen (für + - * /)
  • Multiplikation mit 1, 0, -1
  • Division durch 1, 0, -1
  • Addition/Subtraktion von Termen wie in (2*x)+(x*3)


< Zurück nach oben



Bemerkungen zum Praktikum

Das Programm war ursprünglich als Übungsaufgabe für Studenten angedacht. Ich durfte mich sozusagen schon im Voraus damit beschäftigen. Es wurde in der Auswertung beschlossen, dass die Aufgabe zu schwer für Studenten in den ersten Semestern sei.

Um meine eigenen Leistungen zu relativieren möchte ich hinzufügen, dass Herr Zerbst mit programmiererischem (Über-) Eifer meist schon einen Schritt weiter als ich war. Mein ursprüngliches Programm ist nur noch in wenigen Fragmenten enthalten, einige Ideen wurden übernommen.
Der Hauptteil meiner Arbeit bestand nun darin, das sich ständig weiterentwickelnde Programm zu verstehen und zu ergänzen.

Was lernen wir daraus: Eine klare Aufgabenteilung ist bei solchen Projekten wichtig.

Den kurzen Zeitraum habe ich voll ausgenutzt um meine mathematischen Grundkenntnisse und mein Wissen über Stringverwaltung in C zu erweitern.

Ich bezeichne das Praktikum daher als Erfolg und rate jedem, der in dieser Richtung Ambitionen hat sich an der Universität Leipzig nach einem Praktikumsplatz zu erkundigen.

< Zurück nach oben



Copyright by Hannes Schulz
Homepage - E-Mail


Diese Seite benutzt Stylesheets. Für Netscape unter Version 6 stellt das teilweise ein Problem dar. 'Tschuldigung.