Praktische Informatik I – Der Imperative Kern Mathematiknachhilfe 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 October 9, 2013 1 / 18 Outline 1 Unter- und Oberstufenmathematik 2 Quadratwurzel 3 Erweitern und Kürzen 4 Pascals Dreieck 5 Primfaktorzerlegung 6 Gauß-Elimination Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 2 / 18 In dieser Unterrichtseinheit soll der Nutzen der Rekursion für die Bewältigung von praktisch relevanten Aufgabenstellungen mit informatischen Mitteln deutlich werden. Ausgehend von der Sekundarstufen-Mathematik wird das schnelle Auswählen und Sortieren von Zahlen in Sequenzen besprochen. Sie lernen das Heron-Verfahren zur Quadratwurzelberechnung, den Euklidische Algorithmus zur Bestimmung des größten gemeinsamen Teiler, das Pascal-Dreieck für die allgemeine Binomische Formel, ein Verfahren zur eindeutigen Primfaktorzerlegung, sowie das Gauß’sche Eliminationsverfahren zur Lösung von linearen Gleichungssystemen kennen Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 3 / 18 Outline 1 Unter- und Oberstufenmathematik 2 Quadratwurzel 3 Erweitern und Kürzen 4 Pascals Dreieck 5 Primfaktorzerlegung 6 Gauß-Elimination Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 4 / 18 Heron-Verfahren Programm 1 berechnet die (abgerundete) Quadratwurzel Wir nehmen ein Rechteck, bei dem die eine Kante Länge a hat, für das √ man a sucht. Die zweite Kantenlänge ist 1. Das Verfahren nähert sich iterativ einem Quadrat mit derselben Fläche an. Das Verfahren fußt auf dem Banach’schen Fixpunktsatz Programm 1: Iterative Wurzelberechnung. public class Quiz { public int method(int i) { int a = i; int b = 1; while (a − b > 1) { a = (a + b) / 2; b = i / a; } return (a + b) / 2; } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 5 / 18 Outline 1 Unter- und Oberstufenmathematik 2 Quadratwurzel 3 Erweitern und Kürzen 4 Pascals Dreieck 5 Primfaktorzerlegung 6 Gauß-Elimination Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 6 / 18 Der Euklidische Algorithmus Die rekursive Berechnung des größten gemeinsamen Teilers (engl. greatest common divisor) funktioniert wie folgt: Wenn a mod b = 0 gilt, dann ist gcd(a, b) = b, sonst ist ggT (a, b) = gcd(b, a mod b). Invarianz Zweite Zahl ist kleiner als die erste Zahl mod Rest bei der ganzzahligen Division, wobei der Rest der Division mit Rest a mod b in Java durch a % b dargestellt wird. Der Euklid’sche Algorithmus ist ein Paradebeispiel für ein effizientes rekursives Verfahren: In jedem zweiten Schritt wird eine Eingabezahl mindestens halbiert. Das kleinste gemeinsame Vielfache (kgV) (engl. least common multiplier) von a und b ergibt sich dann aus dem Produkt ab der beiden Zahlen, geteilt durch ihren größten gemeinsamen Teiler. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 7 / 18 Bruchrechnen Das Programm 2 berechnet die Summe von zwei Brüchen inklusive dem Erweitern der Brüche auf den Hauptnenner, sowie dem automatischen Kürzen des Resultats. Programm 2: Bruchrechnen mit Kürzen. public class Fractional { public int gcd(int a, int b) { return a == 0 ? b : gcd(b%a,a); } public int lcm(int a, int b) { return a∗b / gcd(a,b); } public void compute(int a, int b, int c, int d) { System.out.println("(a/b)−>("+(a/gcd(a,b))+"/"+(b/gcd(a,b))+")"); System.out.println("(c/d)−>("+(c/gcd(c,d))+"/"+(d/gcd(c,d))+")"); int k = lcm(b,d); int s = a∗k/b + c∗k/d; System.out.println("sum = ("+(s/gcd(s,k))+"/"+(k/gcd(s,k))+")"); } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 8 / 18 Outline 1 Unter- und Oberstufenmathematik 2 Quadratwurzel 3 Erweitern und Kürzen 4 Pascals Dreieck 5 Primfaktorzerlegung 6 Gauß-Elimination Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 9 / 18 Binomische Formel n k n! ist wichtig u.a. für die = k !(n−k !) P n n k n−k n Darstellung von (a + b) = k =0 k a b . Der Binomialkoeffizient Im Lotto ist ein Sechser bekanntlicherweise mit einer Wahrscheinlichkeit von 1/ 49 zu finden. 6 Es ist nicht schwer, eine rekursive Beschreibung der Funktion n(n − 1)! n n n! = = c(n − 1, k − 1) c(n, k ) = = (n − k )! · k ! k (n − k )!(k − 1)! k k mit c(n, 0) = 1 herzuleiten. Mit dem Programm 3 wird ein Pascal-Dreieck ausgegeben; es gibt in Zeile n die Werte kn für alle k = 0, . . . , n dar. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 10 / 18 Programm 3: Die rekursive Berechnung des Pascal’schen Dreiecks. public class Binomial { private int choose(int n, int k) { return (k == 0) ? 1 : (n ∗ choose(n−1,k−1)) / k; } public void triangle(int m) { int n,k; for (n=0;n<m;n++) { for (k=0;k<=n;k++) { System.out.print("("+m+","+k+")="+choose(n,k)); } System.out.println(); } } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 11 / 18 Outline 1 Unter- und Oberstufenmathematik 2 Quadratwurzel 3 Erweitern und Kürzen 4 Pascals Dreieck 5 Primfaktorzerlegung 6 Gauß-Elimination Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 12 / 18 Eindeutige Zerlegung in Primteiler Die Zerlegung einer Zahl in ihre Primfaktoren nicht nur für die Berechnung des ggTs und des kgVs wichtig: Sie ist (bei Sortierung) eine eindeutige Darstellung. Programm 4 ist eine rekursive Beschreibung, die nach und nach alle Primfaktoren einer Zahl abspaltet. Programm 4: Die rekursive Berechnung der Primfaktorzerlegung. public class PrimeFactor { public void factor(int n) { // prime factorization of n int i=2; // start with first prime factor while((i<n) && (n%i != 0)) i++; // find next factor System.out.println(i); // print found factor if (i < n) factor(n/i); // call with reduced term } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 13 / 18 Outline 1 Unter- und Oberstufenmathematik 2 Quadratwurzel 3 Erweitern und Kürzen 4 Pascals Dreieck 5 Primfaktorzerlegung 6 Gauß-Elimination Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 14 / 18 Lösung von Gleichungssystemen Das Gauß’sche Eliminationsverfahren zur Lösung von linearen Gleichungssystemen Ax = b bei gegebener eindeutiger Lösbarkeit ist nützlich . . . . . . wenn auch numerisch nicht unbedingt stabil: Hier bietet sich die exakte Berechnung der Lösung über die Menge der Bruchzahlen an. Das Programm 5-6 geht grob wie folgt vor: Es bringt die Gleichungen in Standardform und stellt die Koeffizientenmatrix auf. Startpunkt ist i = 1. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 15 / 18 Das Verfahren 1 Falls in der i-ten Zeile die Zahl in der i-ten Spalte 0 ist, wird diese Zeile mit einer Zeile unterhalb ausgetauscht, bei der in der i-ten Spalte eine Zahl steht. Falls keine solche Zeile existiert, ist das Gleichungssystem nicht eindeutig oder auch gar nicht lösbar. Danach wird die i-te Zeile durch die Zahl, in ihrer i-ten Spalte geteilt. Das Diagonalelement wird dadurch 1. 2 Nun wird zu allen anderen Zeilen j mit j 6= i ein geeignetes Vielfaches der Zeile i subtrahuiert, so daß die Zahl in der i-ten Spalte der j-ten Zeile 0 wird. Danach darf in der i-ten Spalte nur noch in der i-ten Zeile eine 1 stehen, sonst stehen nur noch Nullen in dieser Spalte. 3 Falls i < n, wird i um eins erhöht und gehe zurück zu Schritt 1. Die Lösung steht in der letzten Spalte. Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 16 / 18 Programm 5: Ein Löser für lineare Gleichungssysteme. public class Gauss { static final int DIM = 4; double M[][] = { {1.0, 2.0, −1.0, −2.0}, {1.0, 3.0, −1.0, −2.0},{2.0, 1.0, 1.0, 1.0}, {3.0, 1.0, 2.0, 1.0}}; double V[] = {−6.0, −4.0, 11.0, 15.0}; double S[] = new double[DIM]; /∗∗ ∗ Constructor for objects of class Gauss ∗/ public Gauss() { if (solve(M, V)) { for (int k = DIM−1; k>=0; k−−) { S[k] = V[k]; for (int i=(k+1); i<DIM; i++) S[k] −= (M[k][i]∗S[i]); S[k] = S[k] / M[k][k]; } System.out.println("Solution:"); for (int i=0; i<DIM; i++) System.out.print(" " + S[i]); System.out.println(); } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 17 / 18 Programm 6: Ein Löser für lineare Gleichungssysteme. public boolean solve(double M[][], double V[]) { for (int k=0; k<DIM−1; k++) { double max = M[k][k] > 0 ? M[k][k] : −M[k][k]; int m = k; for (int i=k+1; i<DIM; i++) { double abs = M[i][k] > 0 ? M[i][k] : −M[i][k]; if (max < abs) { max = M[i][k]; m = i; } } if (m != k) { for (int i=k; i<DIM; i++) { double t = M[k][i]; M[k][i] = M[m][i]; M[m][i] = t; } double t = V[k]; V[k] = V[m]; V[m] = t; } if(M[k][k] == 0) return false; for (int j=(k+1); j<DIM; j++) { double f = − M[j][k] / M[k][k]; for (int i=k; i<DIM; i++) M[j][i] = M[j][i] + f∗M[k][i]; V[j] = V[j] + f∗V[k]; } } return true; } } Stefan Edelkamp (IAI) PI 1 – Imperativer Kern October 9, 2013 18 / 18