WEB LEXIKON: Ein Blick zurück
Hauptseite | Aktueller Wikipedia-Artikel

Ackermannfunktion



Die Ackermannfunktion ist eine, 1926 von Wilhelm Ackermann erfundene, extrem schnell wachsende Funktion, mit deren Hilfe in der theoretischen Informatik Grenzen von Computer- und Berechnungsmodellenen aufgezeigt werden können. Heute gibt es eine ganze Reihe von Funktionen, die als Ackermannfunktion bezeichnet werden. Diese weisen alle ein ähnliches Bildungsgesetz wie die ursprüngliche Ackermannfunktion auf und haben ein ähnliches Wachstumsverhalten.

Table of contents
1 Entstehungsgeschichte
2 Idee
3 Definition und Varianten
4 Bedeutung in der theoretischen Informatik
5 Anwendungen
6 Implementation
7 Wertetabelle
8 Genauere Betrachtung
9 Sonstiges
10 Literatur
11 Weblinks

Entstehungsgeschichte

1926 vermutete David Hilbert, dass jede berechenbare Funktion primitiv-rekursiv ist. Vereinfacht gesprochen bedeutet dies, dass jede Funktion, die durch einen Computer berechnet werden kann, sich aus einigen wenigen sehr einfachen Regeln zusammensetzen lässt und die Dauer der Berechnung sich im Vorfeld abschätzen lässt. Dies trifft auf nahezu alle in der Praxis vorkommenden Funktionen zu. (Die Ausnahmen sind vorwiegend im Bereich des Compilerbaus zu finden.) Im gleichen Jahr konstruierte Ackermann eine Funktion, die diese Vermutung widerlegt, und veröffentlichte sie 1928. Diese Funktion wird heute ihm zu Ehren Ackermannfunktion genannt. Die Ackermannfunktion kann also von einem Computer in endlicher Zeit ausgewertet werden, ist aber nicht primitiv-rekursiv.

1955 konstruierte Rózsa Péter eine vereinfachte Version, die den gleichen Dienst erweist. Diese Funktion, gelegentlich auch als Ackermann-Péter-Funktion bezeichnet, wird heute vorwiegend benutzt.

Idee

Man betrachtet die Folge , , , Hierbei wird bei jedem Folgeglied die Operation des vorigen Folgeglieds mal auf angewandt, also ist gerade , wobei die Variable -mal vorkommt und so weiter. Die Idee hinter der Ackermannfunktion ist es, diese Folge als Funktion aufzufassen.

Beispiel: Setzt man in obiger Folge und , so erhält man die Folge: 6, 8, 16, 65536, (mit 65536 Zweien), ..., die man auch die Ackermannfunktion zu und nennt. Die letzte aufgeführte Zahl ist bereits wesentlich größer als die geschätzte Anzahl der Atome im gesamten Weltall.

Die Ackermannfunktion ist also eine Funktion, die die folgenden Gleichungen erfüllt:

Ab der vierten Zeile können die Funktionswerte nicht mehr mit herkömmlichen
Operatorenen formuliert werden; man braucht erweiterte Notationen wie beispielsweise den Hyper-Operator.

Definition und Varianten

Die Ackermannfunktion definiert man üblicherweise rekursiv, d.h. man macht für einige Anfangswerte explizite Angaben und gibt eine Anleitung (das Rekursionsschema), wie man weitere Funktionswerte aus den bereits berechneten erhält.

Definition von Ackermann

Ackermann selbst definiert die Funktion auf recht umständliche Weise, gibt aber kurz darauf die folgende äquivalente Definition an.

Dabei ist ein weitere Funktion, die Ackermann nicht weiter beschreibt. (Sie liefert die Startwerte , , , .)

Beispiele:

Wenn man vom Wachstum der Ackermannfunktion spricht, meint man oftmals die Funktion .

Definition von Péter

Rózsa Péter definierte 1955 eine einfachere Version der Ackermannfunktion, die nur zwei Parameter besitzt und zudem ohne die Hilfsfunktion auskommt:

Auch hier meint man im Zusammenhang mit Wachstumsuntersuchungen oftmals die Funktion , wenn man von der Ackermannfunktion spricht.

Bedeutung in der theoretischen Informatik

Wie eingangs schon erwähnt, erfand Ackermann diese Funktion als Beispiel einer Funktion, die nicht primitiv-rekursiv ist, aber berechenbar. Dies ist auch heute noch das wichtigste Anwendungsgebiet der Ackermannfunktion.

Auf der Suche nach den Grenzen von Computern stößt man sehr schnell auf den Begriff der berechenbaren Funktionen. Das sind all die Funktionen, für die man einen Algorithmus angeben kann, mit anderen Worten alle Funktionen, die ein Computer berechnen kann.

Diese Definition stellt einen sehr schnell vor ein Problem, wenn man von einer konkreten Funktion entscheiden möchte, ob sie berechenbar ist. Findet man einen Algorithmus, der die Funktion berechnet, so ist sie offensichtlich berechenbar. Findet man aber keinen Algorithmus, so ist ungewiss ob die Funktion wirklich nicht berechenbar ist oder ob es zwar einen Algorithmus gibt, man ihn aber nicht gefunden hat.

Aus diesem Grund sucht man nach alternativen Definitionen, die einen solchen Nachweis einfacher führen lassen. Ein erster Ansatz hierfür waren die primitiv-rekursiven Funktionen. Dies sind Funktionen, die sich durch einige wenige Regeln aus sehr einfachen Funktionen zusammensetzen lassen.

Einige Zeit vermutete man, dass alle berechenbaren Funktionen primitiv-rekursiv sind, mit den primitiv-rekursiven Funktionen also ein Werkzeug zur Lösung des oben geschilderten Problems gefunden sei. Diese Hoffnung zerstörte die Ackermannfunktion, von der man nachweisen kann, dass sie berechenbar ist, aber nicht primitiv-rekursiv. (Siehe nachfolgenden Expertenabschnitt.)

Anmerkung: Inzwischen weiß man, dass man aus den primitiv-rekursiven Funktionen die berechenbaren erhält, wenn man noch eine weitere Konstruktionsregel, die sogenannte µ-Rekursion, zulässt.

Beweis

Der Beweis, dass die Ackermannfunktion berechenbar ist, aber nicht primitiv-rekursiv, nutzt im Wesentlichen aus, dass die Ackermannfunktion stärker wächst als jede primitiv-rekursive Funktion. Die Details hierfür finden sich in nachfolgendem Expertenabschnitt.

            
Expertenabschnitt: Dieser Abschnitt enthält tiefergehende Informationen, für die zum Teil zusätzliches Fachwissen notwendig ist.

Beweisskizze zur Behauptung, dass die Ackermannfunktion nicht primitiv-rekursiv ist:

  • Als erstes definiert man zu jeder primitiv-rekursiven Funktion g eine Funktion
Diese Funktion gibt das Maximum an, das man mit g erreichen kann, wenn die Summe der Argumente n nicht überschreitet.

  • Sodann zeigt man durch strukturelle Induktion über der induktiven Aufbau der primitiv-rekursiven Funktionen, dass es zu jeder primitiv-rekursiven Funktion g eine natürliche Zahl k gibt, sodass für alle n ≥ k gilt: fg(n) < a(k,n). Anschaulich bedeutet dies, dass die Ackermannfunktion stärker wächst als jede primitiv-rekursive Funktion.

  • Damit beweist man dann wie folgt, dass die Ackermannfunktion nicht primitiv-rekursiv ist:

Angenommen, a(n,k) sei primitiv-rekursiv, dann auch g(n) := a(n,n). Nach der Vorbemerkung gibt es aber ein k, sodass für alle n ≥ k gilt: g(n) < a(k,n). Setzt man hier n = k so erhält man den Widerspruch:

Für Details zum Beweis sehe man z.B. im Buch von Schöning nach. (Siehe Literatur)
            

Anwendungen

Für die Ackermannfunktion gibt es nur sehr wenige Anwendnungen. Die zwei wichtigsten sind als Benchmarktest für rekursive Aufrufe in Programmiersprachen und für die Laufzeitabschätzung im Zusammenhang mit der Union-Find-Datenstruktur.

Benchmark für rekursive Aufrufe

Bei der Einführung von neuen Programmiersprachen, Compilern und Computern möchte man deren Leistungsfähigkeit untersuchen. Eine Möglichkeit hierfür sind Benchmarktests, bei denen ein spezielles Programm benutzt wird, um bestimmte Eigenschaften zu überprüfen.

In diesem Zusammenhang wird die Ackermannfunktion gerne als Benchmark zur Überprüfung von rekursiven Prozeduraufrufenaufrufen benutzt, da ein Programm zur Berechnung der Ackermannfunktion im Wesentlichen nur aus solchen Prozeduraufrufen besteht. In der Definition von Péter wird ja nur direkt berechnet. Die Schwierigkeit bei der Berechnung der Funktionswerte sind also nicht allein deren Größe, sondern die tiefe Verschachtelung der Funktionsaufrufe, die leicht zu einem Stack Overflow führt, also dazu, dass dem System der Speicher ausgeht.

Diese Idee geht zurück auf Yngre Sundblad, der 1971 die Funktion benutzte um diverse Programmiersprachen zu vergleichen. Um zu berechnen, werden Aufrufe getätigt.

Sundblad testete unter anderem, wie groß n gewählt werden kann, damit der Computer noch in der Lage ist, diese Zahl zu berechnen. Damals erreichte er . Zum Vergleich hierzu: Mit Java 1.4.2 mit den Standardspeichereinstellungen erreicht man heutzutage .

Im Laufe der Berechnung werden viele identische Aufrufe mehrfach ausgerechnet. Ein intelligenter Compiler kann dies ausnutzen und die Ergebnisse zwischenspeichern, um solche Aufrufe nur einmal durchführen zu müssen. Damit waren schon 1971 Aufrufe bis durchführbar. Einen bedeutenden Zeitvorteil erhält man auch, wenn man direkt berechnet, statt es rekursiv zu zu expandieren. Die direkte Berechnung von erfordert lineare Zeit in . Die Berechnung von erfordert quadratische Zeit, denn sie führt zu (also für eine Konstante ) verschachtelten Aufrufen von für verschiedene . Die Berechnung von erfordert schließlich eine zu proportionale Zeit (; zur Erklärung der Groß-O-Notation siehe Landau-Symbole).

Laufzeitabschätzung bei Union-Find

Da die Funktion sehr schnell wächst, wächst ihre Umkehrfunktion sehr langsam. Diese Umkehrfunktion taucht in der Laufzeitanalyseanalyse bestimmter Algorithmen auf, zum Beispiel beim Union-Find-Problem. In diesem und anderen Zusammenhängen wird die Ackermannfunktion oft leicht umdefiniert zu einer Funktion mit ähnlichem asymptotischem Verhalten. Diese modifizierten Funktionen sind nicht äquivalent zur Ackermannfunktion, aber nach den Maßstäben der Laufzeitanalyse können sie als äquivalent betrachtet werden. Die Umkehrfunktion der Funktion f ist für jede vorstellbare Eingabegröße kleiner als 4, kann also in der praktischen Analyse von Algorithmen als konstant betrachtet werden.

Implementation

In der Programmiersprache C++ mit den Datenstrukturen der Standard Template Library lässt sich die Ackermannfunktion wie folgt ohne Rekursion implementieren:

int ack(int x, int y)
{
  std::stack<int> stack;
  while (x > 0 || !stack.empty())
  {
    if (x == 0)
    {
      x = stack.top();
      stack.pop();
      y = y + 1;
    }
    else if (y == 0)
    {
      y = 1;
      x = x - 1;
    }
    else
    {
      y = y - 1;
      stack.push(x - 1);
    }
  }
  return y + 1;
}

Die Rekursion wird dabei durch einen Stack simuliert.

Wertetabelle

Die folgende Tabelle zeigt einige Funktionswerte für kleine Werte von und . Die nicht vollständig ausgerechneten Werte sind zu groß, um sie dezimal darzustellen.
Werte von
n\\m 0 1 2 3 4
0 1 2 3 4 5
1 2 3 4 5 6
2 3 5 7 9 11
3 5 13 29 61 125
4 13 65533  ¹ ( Terme)
5 65533
6

¹eine Zahl mit 19729 Dezimalstellen

Genauere Betrachtung

Intuitiv ist die erste Zeile der Wertetabelle (genauer: die Werte von ) einfach eine Liste aller natürlichen Zahlen, und die angewandte mathematische Operation ist die Addition einer 1 zu . Alle folgenden Zeilen enthalten einfach Anweisungen, in dieser Zeile einen Wert zu suchen. Im Falle der Zeile vereinfacht sich diese Anweisung dahingehend, den Wert in der Zeile zu suchen, aber diese Vereinfachung ist schon etwas schwieriger herzuleiten – zum Beispiel:
 
a(1, 2) = a(0, a(1,1))
       = a(0, a(0, a(1,0)))
       = a(0, a(0, 2))
       = a(0, 3)
       = 4

Wir betrachten nun einen komplexeren Fall, nämlich , den ersten Funktionswert, der so groß ist, dass er praktisch nicht dezimal aufgeschrieben werden kann.

a(4, 3) = a(3, a(4, 2))
       = a(3, a(3, a(4, 1)))
       = a(3, a(3, a(3, a(4, 0))))
       = a(3, a(3, a(3, a(3, 1))))
       = a(3, a(3, a(3, a(2, a(3, 0)))))
       = a(3, a(3, a(3, a(2, a(2, 1)))))
       = a(3, a(3, a(3, a(2, a(1, a(2, 0))))))
       = a(3, a(3, a(3, a(2, a(1, a(1, 1))))))
       = a(3, a(3, a(3, a(2, a(1, a(0, a(1, 0)))))))
       = a(3, a(3, a(3, a(2, a(1, a(0, a(0, 1)))))))
       = a(3, a(3, a(3, a(2, a(1, a(0, 2))))))
       = a(3, a(3, a(3, a(2, a(1, 3)))))
       = a(3, a(3, a(3, a(2, a(0, a(1, 2))))))
       = a(3, a(3, a(3, a(2, a(0, a(0, a(1, 1)))))))
       = a(3, a(3, a(3, a(2, a(0, a(0, a(0, a(1, 0))))))))
       = a(3, a(3, a(3, a(2, a(0, a(0, a(0, a(0, 1))))))))
       = a(3, a(3, a(3, a(2, a(0, a(0, a(0, 2))))))
       = a(3, a(3, a(3, a(2, a(0, a(0, 3)))))
       = a(3, a(3, a(3, a(2, a(0, 4)))))
       = a(3, a(3, a(3, a(2, 5))))

Das ist für einige Zeit der einfachste Fall einer solchen Expansion, und es ist nun offensichtlich, warum Funktionswerte wie dieser in der obigen Tabelle selten direkt berechnet werden. Es ist auch interessant festzustellen, wie viele Schritte nötig sind, um schon sehr einfach aussehende Ackermann-Ausdrücke zu vereinfachen. Jede Zeile im vorigen Beispiel ist eine einzige Anwendung eines der drei Teile der Definition der Ackermannfunktion. Wenn wir an dieser Stelle mehrere logische Schritte überspringen, könnten wir zu 13 auswerten und dann versuchen, auszuwerten – das ist 8179. Der nächste Funktionsaufruf, , liefert eine Zahl, die der Zahl der Atome im Universum entspricht, einige Dutzend mal mit sich selbst multipliziert. Diese Zahl wird schließlich in die Berechnung eingesetzt, der irgendwann zu einem Ausdruck der Form ausgeschrieben würde, der aber mit unseren Mitteln nicht mehr aufgeschrieben werden kann.

Der wirklich faszinierende Aspekt der Ackermann-Funktion ist, dass die einzige Berechnung, die neben den rekursiven Aufrufen tatsächlich auftaucht, die Berechnung von ist, die einfach um 1 erhöht.

Sonstiges

a(4,2)

Es sei noch festgehalten, dass der Wert a(4,2), der in Form einer 19727-stelligen Dezimalzahl auf verschiedenen Internetseiten auftaucht, wahrscheinlich nicht mit der rekursiven Definition der Ackermannfunktion praktisch berechnet werden kann.

Die Busy-Beaver-Funktion

1962 gab Tibor Radó mit der Busy-Beaver-Funktion (fleißiger Biber) eine noch stärker wachsende Funktion als die Ackermannfunktion an, die allerdings nicht mehr berechenbar ist.

Literatur

Weblinks

Dieser Artikel befindet sich derzeit im Reviewprozess. Hilf mit, ihn zu verbessern!




     
Das Web Lexikon "Ein Blick zurück" bietet die Moeglichkeit auf einfache Art und Weise in den "alten" Wikipedia-Beiträgen zu blättern. Das Lexikon spiegelt den Stand der freien Wikipedia-Enzyklopädie vom August 2004 wider. Sie finden hier in rund 120.000 Artikel aus dieser Zeit Informationen, Erklärungen, Definitionen, Empfehlungen, Beschreibungen, Auskünfte und Bilder. Ebenso kommen Begriffserklärung, Zusammenfassung, Theorie, Information, Beschreibung, Erklärung, Definition und Geschichte nicht zu kurz. Ein Lexikon das Auskunft, Bericht, Hinweis, Bedeutung, Bild, Aufklärung, Darstellung und Schilderung zu unterschiedlichsten Themen kompakt auf einer Seite bietet.
Impressum ^ nach oben ^