Praktische Informatik I – Der Imperative Kern Rekursive Funktionen Prof. Dr. Stefan Edelkamp Institut für Künstliche Intelligenz Technologie-Zentrum für Informatik und Informationstechnik (TZI) Am Fallturm 1, 28359 Bremen +49-(0)421-218-64007 www.tzi.de/~edelkamp Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 1 / 15 Outline 1 Rekursive Funktionen: Einzeiler, die es in sich haben 2 Fakultät 3 Fibonacci-Zahlen 4 Ackermann-Zahlen 5 Ulam-Zahlen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 2 / 15 Zielstellung In dieser Lerneinheit sollen Sie lernen, dass Programme bei der Ausführung mathematischer Funktionen helfen, indem sie rekursive Definitionen direkt umsetzen und dass die Anzahl der rekursiven Aufrufe die Effizienz des Programmes bestimmt. Das Prinzip der Vollständigen Induktion Beweise vereinfacht Beweise. Es ist dem Domino-Prinzip verwandt – man stößt einen Stein an und nach und nach fallen alle. Neben den Menge der natürlichen Zahlen – die aus der Zahl 1 und einer Menge von Nachfolgern besteht, lassen sich viele interessante mathematischen Funktionen elegant rekursiv formulieren. Tatsächlich ist ein großer Teil der theoretischen Informatik dem Studium der rekursiven Funktionen gewidmet. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 3 / 15 Outline 1 Rekursive Funktionen: Einzeiler, die es in sich haben 2 Fakultät 3 Fibonacci-Zahlen 4 Ackermann-Zahlen 5 Ulam-Zahlen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 4 / 15 Die Vertauschungszahl Die Fakultät einer Zahl n ist die Anzahl von linearen Anordnungen n sich unterscheidender Objekte Die Definition n! = 1 · . . . · n = n · (n − 1)! mit 0! = 1 führt zu einem rekursiven Aufrufverhalten. Programm 1: Die Fakultätsfunktion. public class Factorial { /∗∗ ∗ Computes number of permutations of n objects ∗ ∗ @param n integer number ∗ @return n! ∗/ public long f(long n) { return (n==0) ? 1 : n∗f(n−1); } } Übersetzen Sie und starten Sie es mitNovember dem 21, Aufruf Stefan Edelkamp (IAI)das Programm PI 1 1 – Imperativer Kern 2013 65 / 15 Outline 1 Rekursive Funktionen: Einzeiler, die es in sich haben 2 Fakultät 3 Fibonacci-Zahlen 4 Ackermann-Zahlen 5 Ulam-Zahlen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 6 / 15 Die Vermehrung von Kaninchen Fibonacci-Zahlen sind durch f (n) = f (n − 1) + f (n − 2) mit f (0) = 0 und f (1) = 1 festgelegt. Fibonaccis Aufgabe zu der Vermehrung von Kaninchen: Kaninchen bringen jeden Monat ein neues Paar auf die Welt zu bringen, und sie gebären erstmals im zweiten Monat nach ihrer Geburt. Weil das erste Paar schon im ersten Monat Nachwuchs bekommt, kann man es verdoppeln, so dass nach einem Monat 2 Paare da sind. Von diesen vermehrt sich das erste im zweiten Monat wieder und so gibt es im zweiten Monat 3 Paare. Von denen werden in einem Monat 2 wieder trächtig, so dass im dritten Monat 2 Kaninchenpaare geboren werden; und so sind es dann in diesem Monat 5 Paare. Von denen werden im selben Monat 3 trächtig, usw. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 7 / 15 Programm 2: Fibonaccis Funktion. public class Fibonacci { public int f(int n) { return (n<=1) ? n : f(n−1) + f(n−2); } } Das erste Programm ist durch Mehrfachaufrufe ineffizient (siehe Übung) Fibonacci-Zahlen sind zentral für die Analyse komplexer Strukturen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 8 / 15 Outline 1 Rekursive Funktionen: Einzeiler, die es in sich haben 2 Fakultät 3 Fibonacci-Zahlen 4 Ackermann-Zahlen 5 Ulam-Zahlen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 9 / 15 Nicht zu zähmende Riesen Die Ackermann-Funktion ist eine schnell wachsene Funktion: Für x = 0 ist a(x, y ) = y + 1, für y = 0 ist a(x, y ) = a(x − 1, 1) und sonst ist a(x, y ) = a(x − 1, a(x, y − 1)). Alan Turings Pionierarbeit On computable numbers with an application to the Entscheidungsproblem belegt, wie eng Zahlen mit dem Berechenbarkeitsbegriff zusammenhängen. Mit der Hilfe der Ackermann-Funktion konnten die Grenzen von Computerberechnungsmodellen aufgezeigt werden. Programm 3: Die Ackermann-Funktion. public class Ackermann { public int a(int n, int m) { return (n == 0) ? m+1 : (m == 0) ? a(n−1,1) : a(n−1,a(n,m−1)); } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 10 / 15 Outline 1 Rekursive Funktionen: Einzeiler, die es in sich haben 2 Fakultät 3 Fibonacci-Zahlen 4 Ackermann-Zahlen 5 Ulam-Zahlen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 11 / 15 Kein Ende in Sicht? Die folgende interessante Funktion u wurde von Stanislaw Marcin Ulam beschrieben: Für x = 1 ist u(x) = 1, für x > 1 und x gerade ist u(x) = u(bx/2c), ansonsten ist u(x) = 3x + 1. Der Wert der Ulam-Funktion ist (soweit bekannt) immer 1. Die Eingabe von 6 im Programm 4 ergibt u(6), u(3), u(10), u(5), u(16), u(8), u(4), u(2), u(1), 1 Programm 4: Die Ulam-Funktion. public class Ulam { public int u(int n) { System.out.print("u("+n+"),"); return n == 1 ? 1 : n%2 == 0 ? u(n/2) : u(3∗n+1); } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 12 / 15 Peano Axiome Durch die folgende Axiomatisierung der natürlichen Zahlen nach den Peano-Axiomen sind viele mathematische Funktionsdefinition inhärent rekursiv 0 ist eine natürliche Zahl. jede natürliche Zahl n hat eine natürliche Zahl n0 als Nachfolger. 0 ist kein Nachfolger einer natürlichen Zahl. natürliche Zahlen mit gleichem Nachfolger sind gleich. enthält X die 0 und mit jeder natürlichen Zahl n auch deren Nachfolger n0 , so bilden die natürlichen Zahlen eine Teilmenge von X . Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 13 / 15 Geschlossene Formen Manchmal lassen sich rekursive Funktionen in geschlossener Form ausdrücken oder abschätzen. Das hilft bei der Bestimmung des Funktionswachstums So kann man überprüfen, dass n! ≥ (n/2)n/2 gilt. Merke: Rekursive Funktionen erhalten in ihrem Rumpf mindestens einmal den eigenen Bezeichner. Ein Aufruf endet nur dann nach einer endlichen Anzahl von Schritten, wenn die Abbruchbedingung erfüllt ist. Durch Speichern von Zwischenergebnissen kann man Mehrfachberechnungen vermeiden. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 14 / 15 Diskussion Wächst jede rekursiv definierte Zahl schnell? Welches Problem ergibt sich bei Programmen mit mehr als einem rekursiven Aufruf? Wie kann man es angehen? Kann jedes rekursive Programm in ein iteratives Programm umgewandelt werden? Stefan Edelkamp (IAI) PI 1 – Imperativer Kern November 21, 2013 15 / 15