Schleifensteuerung, Darstellung von Funktionen und Polynome


  1. Durch die endliche Rechengenauigkeit bei Floating Point (im Gegensatz zu ganzen) Zahlen kann es schon bei den einfachsten Operationen zu unerwarteten Ergebnissen kommen: Untersuche, wie oft die folgende Schleife in F
    real::x
    ...
    do x=1.0,2.0,0.1
      ...
    end do
    bzw. in C
    float x;
    ...
    for(x=1.0;x<=2.0;x=x+0.1) {
      ...
    }
    tatsächlich ausgeführt wird. Hängt das Verhalten von Sprache und Compiler ab?
    Dies ist einer der Gründe, warum die Verwendung von nicht-ganzzahligen Schleifenzählern, obwohl in F9x geduldet, in F verpönt ist. Ein rigoroser F-Compiler sollte in diesem Fall auch einen Fehler melden.
  2. In der Statistischen Physik wird häufig die für große n gültige Näherung
    logn! » nlogn-n
    verwendet. Schreibe ein Programm, das für ein vorgegebenes n diese sowie die verbesserte Stirling'sche Approximation
    logn! » nlogn-n+log
    Ö
     

    2pn
     
    mit dem exakten Wert vergleicht, und berechne den relativen Fehler beider Näherungen.
    Da man bei naiver Berechnung von n! sehr bald den standardmäßig am Computer darstellbaren Bereich ganzer Zahlen überschreitet, empfiehlt es sich, logn! als
    logn! = log1+log2+log3+¼+logn
    zu berechnen. Die Zahl p kann man z.B. mit Hilfe der Funktion atan aus der Beziehung tan-1(1)=p/4 bekommen.
  3. Wie viele andere analytische Funktionen auch, läßt sich die Exponentialfunktion im Prinzip durch eine Reihenentwicklung
    ex = ¥
    å
    k=0 
    xk

    k!
    darstellen. (Dies ist jedoch nicht die Art und Weise, wie in Programmiersprachen "eingebaute Funktionen" üblicherweise implementiert werden!)  Schreibe ein kurzes Programm, das ein Argument x und einen Index n einliest, die Exponentialfunktion durch Summation aller Terme der Reihenentwicklung bis einschließlich k=n approximiert und mit dem "exakten" Wert der eingebauten Funktion exp vergleicht.
    Hinweis: Da sowohl xk als auch k! sehr schnell mit k wachsen können, empfiehlt es sich, nicht für jeden Summanden Zähler und Nenner separat zu berechnen und dann durch einander zu dividieren, sondern jeweils den k-ten Term durch Multiplikation mit x/k aus dem (k-1)-ten zu bilden.
  4. Wird eine analytische Funktion durch eine endliche Reihenentwicklung approximiert, so bedeutet dies, daß sie eigentlich durch ein Polynom (von eventuell sehr hohem Grad) dargestellt wird, z.B. für den Logarithmus
    ln(1+x) » n
    å
    k=1 
    (-1)(k+1) xk

    k
    = x - x2

    2
    + x3

    3
    + ¼+ (-1)(n+1) xn

    n
    Da Polynome oft numerisch ungünstige Eigenschaften haben, ist es besser, sie nicht wie oben angeschrieben, sondern nach dem Hornerschema "von innen nach außen" auszuwerten, d.h. in diesem Fall
    ln(1+x) » x é
    ë
    1-x é
    ë
    1

    2
    -x é
    ë
    1

    3
    -x é
    ë
    ¼-x é
    ë
    1

    n-1
    - x

    n
    ù
    û
    ¼ ù
    û
    ù
    û
    ù
    û
    ù
    û
    wobei man mit dem Term in den innersten Klammern beginnt und sich nach außen durcharbeitet. Das hat den Vorteil, daß in jedem Schritt x nur linear vorkommt und nicht hohe Potenzen von x direkt miteinander kombiniert werden müssen.
    Schreibe ein Programm, das nach Eingabe von x und n das obige Approximationspolynom sowohl nach dem naiven als auch nach dem Hornerschema berechnet. Um die Unterschiede besser sichtbar zu machen, sollten die Rechnungen in "einfacher Präzision" (Typ real in F bzw.  float in C) durchgeführt werden.
    Hinweis: Untersuche insbesondere das Verhalten bei |x| » 1.
    Da die logarithmische Reihe sehr langsam konvergiert, wird allerdings der Wert des Polynoms i.a. nicht mit dem exakten Ergebnis ln(1+x) der eingebauten Funktion log übereinstimmen: Während für kleine n nur der Grenzwert der Reihe noch nicht erreicht ist, können für hohe Polynomgrade selbst beim Hornerschema Rundungsfehler das Resultat verfälschen.
  5. Ein (unendlicher) Kettenbruch ist ein Ausdruck der Form
    a0 + b1

    a1+
      b2

    a2+
      b3

    a3+
     ¼
    Dies ist eine vereinfachte Schreibweise für
    a0 + b1

    a1+ b2

    a2+ b3

    a3+¼
    Eine naive (aber nicht immer numerisch gutartige) Methode, einen Kettenbruch auszuwerten, besteht darin, ab einer gewissen Stufe die durch Punkte angedeuteten Beiträge zu vernachlässigen und, z.B. mit dem Quotienten (bn/an) beginnend, den Bruch von "unten her" durch wiederholtes Dividieren zu berechnen. Kettenbrüche spielen eine wichtige Rolle als Alternativen zu Reihenentwicklungen von mathematischen Funktionen, weil sie oft schneller konvergieren oder überhaupt einen größeren Konvergenzbereich besitzen.
    Schreibe ein Programm, das die Logarithmusfunktion des vorigen Beispiels mit Hilfe der Kettenbruchentwicklung
    log(1+x) = x

    1+
      x

    2+
      x

    3+
      4x

    4+
      4x

    5+
      9x

    6+
      9x

    7+
     ¼
    approximiert (Abbruch nach dem n-ten Term) und vergleiche die Konvergenzgeschwindigkeit dieser Entwicklung mit der der Taylorreihe.
    Im Unterschied zur Taylorreihe, die nur für |x| < 1 konvergiert, sollte die Kettenbruchentwicklung für alle -1 < x < ¥ gültig sein. Untersuche daher auch, ob bzw. in welchem Bereich die erhaltenen Werte mit jenen der Funktion log übereinstimmen.



File translated from TEX by TTH, version 3.80.
On 6 Mar 2008, 17:39.