Schleifen Zählschleife for ◮ Mathematische Symbole ◮ Zählschleife Pn j=1 und ◮ Schleifen führen einen oder mehrere Befehle wiederholt aus ◮ In Aufgabenstellung häufig Hinweise, wie • Vektoren & Matrizen • Laufvariablen j = 1, . . . , n P • Summen nj=1 aj := a1 + a2 + · · · + an Q • Produkte nj=1 aj := a1 · a2 · · · an Qn j=1 • Text wie z.B. solange bis oder solange wie ◮ ◮ for Man unterscheidet • Zählschleifen (for): Wiederhole etwas eine gewisse Anzahl oft • Bedingungsschleifen: Wiederhole etwas bis eine Bedingung wahr bzw. falsch ist. 64 65 Die for-Schleife ◮ for (init. ; cond. ; step-expr.) statement ◮ Ablauf einer for-Schleife • (1) Ausführen der Initialisierung init. • (2) Abbruch, falls Bedingung cond. nicht erfüllt • (3) Ausführen von statement • (4) Ausführen von step-expr. • (5) Sprung nach (2) ◮ 1 2 3 4 5 6 7 8 9 10 11 statement ist • entweder eine Zeile • oder mehrere Zeilen in geschwungenen Klammern { ... }, sog. Block Ein weiteres elementares Beispiel 1 2 3 4 5 6 7 8 9 10 for (j=5; j>0 ; j=j-1) printf("%d ",j); printf("\n"); main() { int j = 0; int k = 0; for (j=5, k=0; j>0; j=j-1, k=k+1) printf("j=%d, k=%d\n",j,k); } ◮ init. und step-expr. können aus mehreren Befehlen bestehen (jeweils durch Kommata getrennt) ◮ Output: j=5, k=0 j=4, k=1 j=3, k=2 j=2, k=3 j=1, k=4 #include <stdio.h> main() { int j = 0; #include <stdio.h> } ◮ j=j-1 in 7 ist Zuweisung, keine math. Gleichheit! ◮ Output: 5 4 3 2 1 66 67 Minimum eines Vektors Vektor einlesen & ausgeben 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <stdio.h> void scanvector(double input[], int dim) { int j; for (j=0; j<dim; j=j+1) { input[j] = 0; printf("%d: ",j); scanf("%lf",&input[j]); } } void printvector(double output[], int dim) { int j; for (j=0; j<dim; j=j+1) printf("%f ",output[j]); printf("\n"); } main() { double x[5]; scanvector(x,5); printvector(x,5); } ◮ Funktionen müssen Länge von Arrays kennen! • d.h. zusätzlicher Input-Parameter nötig ◮ Arrays werden mit Call by Reference übergeben! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> void scanvector(double input[], int dim) { int j; for (j=0; j<dim; j=j+1) { input[j] = 0; printf("%d: ",j); scanf("%lf",&input[j]); } } double min(double input[], int dim) { int j; double minval = input[0]; for (j=1; j<dim; j=j+1) { if (input[j]<minval) minval = input[j]; } return minval; } main() { double x[5]; scanvector(x,5); printf("Minimum des Vektors ist %f\n", min(x,5)); } 68 69 Beispiel: Summensymbol Beispiel: Summensymbol ◮ Berechnung der Summe S = n X X 1 2 3 4 5 6 7 8 9 10 11 12 13 14 aj : j=1 • Abkürzung N X aj := a0 + a1 + . . . + aN j=0 ◮ Definiere theoretische Hilfsgröße Sk = k X ak j=1 ◮ ◮ Dann gilt • S1 = a 1 • S2 = S1 + a 2 • S3 = S2 + a3 etc. Realisierung also durch n-maliges Aufsummieren • ACHTUNG: Zuweisung, keine Gleichheit ∗ S = a1 ∗ S = S + a2 ∗ S = S + a3 etc. 70 X #include <stdio.h> main() { int j = 0; int n = 100; int sum = 0; for (j=1; j<=n; j=j+1) sum = sum+j; printf("sum_{j=1}^{%d} j = %d\n",n,sum); } Pn ◮ Programm berechnet ◮ Output: sum {j=1}^{100} j = 5050 ◮ ACHTUNG: Bei iterierter Summation nicht vergessen, Ergebnisvariable auf Null zu setzen vgl. Zeile 8 • Anderenfalls: Falsches/Zufälliges Ergebnis! ◮ In diesem Beispiel ist es effizienter (besser!) • sum=1 zu initialisieren, Zeile 8 • Schleife bei j=2 zu beginnen, Zeile 10 j=1 j für n = 100. 71 Beispiel: Produktsymbol 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Y #include <stdio.h> Matrix-Vektor-Multiplikation main() { int j = 0; int n = 5; int fak = 1; for (j=1; j<=n; j=j+1) fak = fak*j; Man darf for-Schleifen schachteln • Typisches Beispiel: Matrix-Vektor-Multiplikation ◮ Seien A ∈ RM ×N Matrix, x ∈ RN Vektor ◮ Def b := Ax ∈ RM durch bj = printf("%d! = %d\n",n,fak); N −1 X Ajk xk k=0 • d.h. äußere Schleife über j, innere für Summe } Qn ◮ Prg berechnet Faktorielle n! = ◮ Output: 5! = 120 ◮ ACHTUNG: Bei iteriertem Produkt nicht vergessen, Ergebnisvariable auf Eins zu setzen vgl. Zeile 8 • Anderenfalls: Falsches/Zufälliges Ergebnis! ◮ ◮ j=1 j für n = 5. ◮ Ax = b ist also Schreibweise für lineares GLS A00 x0 A10 x0 A20 x0 .. . AM −1,0x0 + + + + A01 x1 A11 x1 A21 x1 .. . AM −1,1x1 +...+ +...+ +...+ +...+ A0,N −1xN −1 A1,N −1xN −1 A2,N −1xN −1 .. . AM −1,N −1xN −1 = = = b0 b1 b2 .. . = bM −1 In diesem Beispiel ist es effizienter (besser!) • Schleife bei j=2 zu beginnen, Zeile 10 72 73 Matrix spaltenweise speichern ◮ math. Bibliotheken speichern Matrizen idR. spaltenweise als Vektor • A ∈ RM ×N , gespeichert als a ∈ RM N • a = (A00, A10, ..., AM −1,0, A01, A11, . . . , AM −1,N −1) • Ajk entspricht also aℓ mit ℓ = j + k · M ◮ Matrix-Vektor-Produkt P −1 • b := Ax ∈ RM , bj = N k=0 Ajk xk • mit double A[M][N]; Schachtelung von Schleifen ◮ Man darf for-Schleifen schachteln ◮ Typisches Beispiel: Matrix-Vektor-Multiplikation: • A ∈ RM ×N , x ∈ RN , P −1 • b := Ax ∈ RM , bj = N k=0 Ajk xk . ∗ Äußere Schleife über j = 0, . . . , M − 1 P −1 ∗ Innere Schleife für Summe N k=0 for (j=0; j<M; j=j+1) { b[j] = 0; for (k=0; k<N; k=k+1) { b[j] = b[j] + A[j][k]*x[k]; } } for (j=0; j<M; j=j+1) { b[j] = 0; for (k=0; k<N; k=k+1) { b[j] = b[j] + A[j][k]*x[k]; } } ◮ ◮ ACHTUNG: Init. b[j] = 0 nicht vergessen! Matrix-Vektor-Produkt (spaltenweise gespeichert) • mit double A[M*N]; for (j=0; j<M; j=j+1) { b[j] = 0; for (k=0; k<N; k=k+1) { b[j] = b[j] + A[j+k*M]*x[k]; } } 74 75 MinSort (= Selection Sort) ◮ Gegeben: Ein Vektor x ∈ Rn ◮ Ziel: Sortiere x, sodass x1 ≤ x2 ≤ · · · ≤ xn ◮ Algorithmus (1. Schritt) • suche Minimum xk von x1, . . . , xn • vertausche x1 und xk , d.h. x1 ist kleinstes Elt. ◮ Algorithmus (2. Schritt) • suche Minimum xk von x2, . . . , xn • vertausche x2 und xk , d.h. x2 zweit kleinstes Elt. ◮ nach n − 1 Schritten ist x sortiert ◮ Hinweise zur Realisierung (vgl. UE) • Länge n ist Konstante im Hauptprogramm ∗ d.h. n ist im Hauptprg nicht veränderbar • aber n ist Inputparameter der Funktion minsort ∗ d.h. Funktion arbeitet für beliebige Länge 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <stdio.h> #define DIM 5 void scanvector(double input[], int dim) { int j; for (j=0; j<dim; j=j+1) { input[j] = 0; printf("%d: ",j); scanf("%lf",&input[j]); } } void printvector(double output[], int dim) { int j; for (j=0; j<dim; j=j+1) { printf("%f ",output[j]); } printf("\n"); } void minsort(double vector[], int dim) { int j, k, argmin; double tmp; for (j=0; j<dim-1; j=j+1) { argmin = j; for (k=j+1; k<dim; k=k+1) { if (vector[argmin] > vector[k]) { argmin = k; } } if (argmin > j) { tmp = vector[argmin]; vector[argmin] = vector[j]; vector[j] = tmp; } } } main() { double x[DIM]; scanvector(x,DIM); minsort(x,DIM); printvector(x,DIM); } 76 77 Die while while-Schleife Bedingungsschleifen ◮ Bedingungsschleife ◮ kopfgesteuert vs. fußgesteuert ◮ Operatoren ++ und -- ◮ while ◮ do - while ◮ Formal: ◮ Vor jedem Durchlauf wird condition geprüft & Abbruch, falls nicht erfüllt • sog. kopfgesteuerte Schleife ◮ Eventuell also kein einziger Durchlauf! ◮ statement kann Block sein 1 2 3 4 5 6 7 8 9 10 11 12 13 ◮ 78 while(condition) statement #include <stdio.h> main() { int counter = 5; while (counter > 0) { printf("%d ",counter); counter = counter-1; } printf("\n"); } Output: 5 4 3 2 1 79 Operatoren ++ Operatoren ++ und -◮ ++a und a++ sind arithmetisch äquivalent zu a=a+1 ◮ Zusätzlich aber Auswertung von Variable a ◮ Präinkrement ++a • Erst erhöhen, dann auswerten ◮ Postinkrement a++ • Erst auswerten, dann erhöhen 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ◮ ◮ Analog zu a++ und ++a gibt es • Prädekrement --a ∗ Erst verringern, dann auswerten • Postdekrement a-∗ Erst auswerten, dann verringern ◮ Wenn Operator ++ nur Kurzform für a=a+1 (z.B. in Zählschleifen) sollte man Präinkrement ++a nehmen ◮ Beachte Unterschied in Bedingungsschleife! #include <stdio.h> main() { int a = 0; int b = 43; 1 2 3 4 5 6 7 8 9 10 11 12 printf("1) a=%d, b=%d\n",a,b); b = a++; printf("2) a=%d, b=%d\n",a,b); b = ++a; printf("3) a=%d, b=%d\n",a,b); } Output: 1) a=0, b=43 2) a=1, b=0 3) a=2, b=2 #include <stdio.h> main() { int counter = 5; while (--counter>0) { printf("%d ",counter); } printf("\n"); } ◮ Output: 4 3 2 1 (für --counter in 7) ◮ Output: 4 3 2 1 0 (für counter-- in 7) 80 81 Euklids Algorithmus Euklids Algorithmus ◮ Gegeben: zwei ganze Zahlen a, b ∈ N ◮ Gesucht: größter gemeinsamer Teiler ggT (a, b) ∈ N ◮ Euklidischer Algorithmus: • Falls a = b, gilt ggT (a, b) = a • Vertausche a und b, falls a < b • Dann gilt ggT (a, b) = ggT (a − b, b), denn: ∗ Sei g Teiler von a, b ∗ d.h. ga0 = a und gb0 = b mit a0, b0 ∈ N, g ∈ N ∗ also g(a0 − b0) = a − b und a0 − b0 ∈ N ∗ d.h. g teilt b und a − b ∗ d.h. ggT (a, b) ≤ ggT (a − b, b) ∗ analog ggT (a − b, b) ≤ ggT (a, b) • Ersetze a durch a − b, wiederhole diese Schritte ◮ Erhalte ggT (a, b) nach endlich vielen Schritten: • Falls a 6= b, wird also n := max{a, b} ∈ N pro Schritt um mindestens 1 kleiner • Nach endl. Schritten gilt also nicht mehr a 6= b 82 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> main() { int a = 200; int b = 110; int tmp = 0; printf("ggT(%d,%d)=",a,b); while (a != 0) { if ( a < b) { tmp = a; a = b; b = tmp; } a = a-b; } printf("%d\n",b); } ◮ berechnet ggT von a, b ∈ N ◮ basiert auf ggT (a, b) = ggT (a − b, b) für a > b ◮ Für a = b gilt ggT (a, b) = b und a − b = 0 ◮ Output: ggT(200,110)=10 83 Ein weiteres Beispiel Die do-while do-while-Schleife ◮ Formal: ◮ Nach jedem Durchlauf wird condition geprüft & Abbruch, falls nicht erfüllt • sog. fußgesteuerte Schleife ◮ Also mindestens ein Durchlauf! ◮ statement kann Block sein 1 2 3 4 5 6 7 8 9 10 11 12 13 do statement while(condition) #include <stdio.h> main() { int counter = 5; do { printf("%d ",counter); } while (--counter>0); printf("\n"); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> main() { int x[2] = {0,1}; int tmp = 0; int c = 0; printf("c="); scanf("%d",&c); printf("%d %d ",x[0],x[1]); do { tmp = x[0]+x[1]; x[0] = x[1]; x[1] = tmp; printf("%d ",tmp); } while(tmp<c); printf("\n"); } ◮ Fibonacci-Folge strebt gegen unendlich • x0 := 0, x1 := 1 und xn+1 := xn−1 + xn für n ∈ N ◮ Output: 5 4 3 2 1 ◮ Ziel: Berechne erstes Folgenglied mit xn > c für gegebene Schranke c ∈ N ◮ counter-- in 11 liefert Output: 5 4 3 2 1 0 ◮ für Eingabe c = 1000 erhalte Output: c=1000 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 84 85 Kommentarzeilen Kommentarzeilen ◮ ◮ werden vom Interpreter/Compiler ausgelassen ◮ nur für den Leser des Programmcodes ◮ notwendig, um eigene Programme auch später noch zu begreifen • deshalb brauchbar für Übung? ◮ notwendig, damit andere den Code verstehen • soziale Komponente der Übung? ◮ extrem brauchbar zum debuggen • Teile des Source-Code “auskommentieren”, sehen was passiert... • vor allem bei Fehlermeldungen des Parser ◮ Wichtige Regeln: • nie dt. Sonderzeichen verwenden • nicht zu viel und nicht zu wenig • zu Beginn des Source-Codes stets Autor & letzte Änderung kommentieren ∗ vermeidet das Arbeiten an alten Versionen... wozu Kommentarzeilen? ◮ // ◮ /* . . . */ 86 87 Kommentarzeilen in C 1 2 3 4 5 6 7 8 9 10 11 12 13 ◮ ◮ ◮ #include <stdio.h> Beispiel: Euklids Algorithmus main() { // printf("1 "); printf("2 "); /* printf("3"); printf("4"); */ printf("5"); printf("\n"); } Gibt in C zwei Typen von Kommentaren: • einzeiliger Kommentar ∗ eingeleitet durch //, geht bis Zeilenende ∗ z.B. Zeile 5 ∗ stammt eigentlich aus C++ • mehrzeiliger Kommentar ∗ alles zwischen /* (Anfang) und */ (Ende) ∗ z.B. Zeile 7 - 10 ∗ darf nicht geschachtelt werden! − d.h. /* ... /* ... */ ... */ ist Syntaxfehler Vorschlag • Verwende // für echte Kommentare • Verwende /* ... */ zum Debuggen 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // author: Dirk Praetorius // last modified: 19.10.2006 // Euklids Algorithmus zur Berechnung des ggT // basiert auf ggT(a,b) = ggT(a-b,b) fuer a>b // Abbruch, wenn a==b [dann a-b=0 und ggT(a,b)=b] int euklid(int a, int b) { int tmp = 0; while (a != 0) { // garantiere a>b, also ggf. vertauschen if ( a < b) { tmp = a; a = b; b = tmp; } // Reduktion ggT(a,b)=ggT(a-b,b) a = a-b; } return b; } Output: 2 5 88 89 Speichereinheiten Ganzzahlen ◮ 1 Bit = 1 b = kleinste Einheit, speichert 0 oder 1 ◮ 1 Byte = 1 B = Zusammenfassung von 8 Bit ◮ 1 Kilobyte = 1 KB = 1024 Byte ◮ 1 Megabyte = 1 MB = 1024 KB ◮ 1 Gigabyte = 1 GB = 1024 MB Speicherung von Zahlen ◮ Bits, Bytes etc. ◮ short, int, long ◮ unsigned ◮ Zur Speicherung von Zahlen wird je nach Datentyp fixe Anzahl an Bytes verwendet ◮ Konsequenz: • pro Datentyp gibt es nur endlich viele Zahlen ∗ es gibt jeweils größte und kleinste Zahl! Ganzzahlen 90 ◮ Mit n Bits kann man 2n Ganzzahlen darstellen ◮ Standardmäßig betrachtet man • entweder alle ganzen Zahlen in [0, 2n − 1] • oder alle ganzen Zahlen in [−2n−1, 2n−1 − 1] 91 2 Milliarden sind nicht viel! Integer-Arithmetik ◮ exakte Arithmetik innerhalb [intmin, intmax] ◮ Überlauf: Ergebnis von Rechnung > intmax ◮ Unterlauf: Ergebnis von Rechnung < intmin ◮ Integer-Arithmetik in C ist Modulo-Arithmetik • d.h. Zahlenbereich ist geschlossen ∗ intmax + 1 liefert intmin ∗ intmin − 1 liefert intmax 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ◮ #include <stdio.h> main() { int j = 0; int n = 8*sizeof(int); // number bits per int int min = 1; // compute 2^(n-1) for (j=1; j<n; ++j) { min = 2*min; } printf("n=%d, min=%d, max=%d\n",n,min,min-1); } man beobachtet [−2n−1, 2n−1 − 1] mit n = 32 ◮ Output: n=32, min=-2147483648, max=2147483647 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> main() { int n = 1; int fak = 1; do { ++n; fak = n*fak; printf("n=%d, n!=%d\n",n,fak); } while (fak < n*fak); printf("n=%d, n!>%d\n",n+1,n*fak); } ◮ Output: n=2, n!=2 n=3, n!=6 n=4, n!=24 n=5, n!=120 n=6, n!=720 n=7, n!=5040 n=8, n!=40320 n=9, n!=362880 n=10, n!=3628800 n=11, n!=39916800 n=12, n!=479001600 n=13, n!=1932053504 n=14, n!>-653108224 92 93 Variablentypen char Variablentypen short short, int int, long ◮ n Bits ⇒ 2n Ganzzahlen ◮ In C sind short, int, long mit Vorzeichen • d.h. ganze Zahlen in [−2n−1, 2n−1 − 1] ◮ ◮ ◮ Ganzzahlen ≥ 0 durch zusätzliches unsigned • d.h. ganze Zahlen in [0, 2n − 1] • z.B. unsigned int var1 = 0; Es gilt stets short ≤ int ≤ long • Standardlängen: 2 Byte (short), 4 Byte (int) • Bisweilen für long keine Arithmetik vorgesehen! ∗ Compiler liefert trotzdem keinen Fehler • Man sollte nur int (und short) verwenden Platzhalter in printf und scanf Datentyp short int unsigned short unsigned int printf %d %d %u %u scanf %d %u ◮ char ist Ganzzahl-Typ, idR. 1 Byte ◮ Zeichen sind intern Ganzzahlen zugeordnet • idR. ASCII-Code • siehe z.B. http://www.asciitable.com/ ◮ ASCII-Code eines Buchstabens erhält man durch einfache Hochkommata • Deklaration char var = ’A’; weist var ASCII-Code des Buchstabens A zu ◮ Platzhalter eines Zeichens für printf und scanf • %c als Zeichen • %d als Ganzzahl 1 2 3 4 5 6 7 8 9 ◮ 94 #include <stdio.h> main() { char var = ’A’; printf("sizeof(var) = %d\n", sizeof(var)); printf("%c %d\n",var,var); } Output: sizeof(var) = 1 A 65 95 Definition ◮ SATZ: Zu x ∈ R existieren • Vorzeichen σ ∈ {±1} • Ziffern aj ∈ {0, 1} • Exponent e ∈ Z sodass gilt x = σ Gleitkommazahlen ∞ X ak 2−k 2e k=1 ◮ Darstellung ist nicht eindeutig, da z.B. 1 = ∞ X 2−k k=1 ◮ analytische Binärdarstellung ◮ Gleitkomma-Zahlsystem F(2, M, emin, emax) ◮ schlecht gestellte Probleme ◮ Rechenfehler und Gleichheit ◮ Gleitkommazahlen ◮ Gleitkommazahlsystem F(2, M, emin, emax) ⊂ Q • Mantissenlänge M ∈ N • Exponentialschranken emin < 0 < emax ◮ x ∈ F hat Darstellung x = σ float, double M X ak 2−k 2e mit k=1 • Vorzeichen σ ∈ {±1} • Ziffern aj ∈ {0, 1} mit a1 = 1 ∗ sog. normalisierte Gleitkommazahl • Exponent e ∈ Z mit emin ≤ e ≤ emax ◮ Darstellung von x ∈ F ist eindeutig (Übung!) ◮ Ziffer a1 muss nicht gespeichert werden • implizites erstes Bit 96 97 Beweis von Satz Anmerkungen zum Satz ◮ o.B.d.A. x ≥ 0 — Multipliziere ggf. mit σ = −1. ◮ Sei e ∈ N0 mit 0 ≤ x < 2e ◮ o.B.d.A. x < 1 — Teile durch 2e ◮ Konstruktion der Ziffern aj durch Bisektion: ◮ Satz gilt für jede Basis b ∈ N≥2 • Ziffern dann aj ∈ {0, 1, . . . , b − 1} ◮ Dezimalsystem b = 10 ist übliches System • 47.11 = (4·10−1 +7·10−2 +1·10−3 +1·10−4)∗102 ∗ a1 = 4, a2 = 7, a3 = 1, a4 = 1, e = 2 ◮ Induktionsbehauptung: Ex. Ziffern aj ∈ {0, 1} n X • sodass xn := ak 2−k erfüllt x ∈ [xn, xn + 2−n ) ◮ Induktionsanfang: Es gilt x ∈ [0, 1) • falls x ∈ [0, 1/2), wähle a1 = 0, d.h. x1 = 0 • falls x ∈ [1/2, 1), wähle a1 = 1, d.h. x1 = 1/2 ∗ x1 = a1/2 ≤ x ∗ x < (a1 + 1)/2 = x1 + 2−1 k=1 ◮ Es folgt |xn − x| ≤ 2−n , also x = ∞ X ak 2−k Mit b = 2 sind Brüche genau dann als endliche Summe darstellbar, wenn Nenner Zweierpotenz Arithmetik für Gleitkommazahlen ◮ Ergebnis Inf bei Überlauf ◮ Ergebnis -Inf bei Unterlauf ◮ Arithmetik ist approximativ, nicht exakt Induktionsschritt: Es gilt x ∈ [xn, xn + 2−n) • falls x ∈ [xn, xn + 2−(n+1) ), wähle an+1 = 0, d.h. xn+1 = xn • falls x ∈ [xn + 2−(n+1) , xn + 2−n), wähle an+1 = 1 ∗ xn+1 = xn + an+12−(n+1) ≤ x ∗ x < xn + (an+1 +1)2−(n+1) = xn+1 + 2−(n+1) ◮ ◮ Schlechte Kondition ◮ Eine Aufgabe ist numerisch schlecht gestellt, falls kleine Änderungen der Daten auf große Änderungen im Ergebnis führen • z.B. hat Dreieck mit gegebenen Seitenlängen einen rechten Winkel? • z.B. liegt gegebener Punkt auf Kreisrand? k=1 98 99 Rechenfehler ◮ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Aufgrund von Rechenfehlern darf man Gleitkommazahlen nie auf Gleichheit überprüfen • Statt x = y prüfen, ob Fehler |x − y| klein ist • z.B. |x − y| ≤ ε · max{|x|, |y|} mit ε = 10−13 #include <stdio.h> #include <math.h> Variablentypen float float, double ◮ Gleitkommazahlen sind endliche Teilmenge von Q ◮ float ist idR. einfache Genauigkeit nach IEEE-754-Standard • F(2, 24, −125, 128) → 4 Byte • sog. single precision • ca. 7 signifikante Dezimalstellen ◮ double ist idR. doppelte Genauigkeit nach IEEE-754-Standard • F(2, 53, −1021, 1024) → 8 Byte • sog. double precision • ca. 16 signifikante Dezimalstellen ◮ Für long double ist auf vielen Compilern keine Arithmetik vorgesehen • Man sollte nur double (und float) verwenden ◮ Platzhalter in printf und scanf main() { double x = (116./100.)*100.; printf("x=%f\n",x); printf("floor(x)=%f\n",floor(x)); if (x==116.) { printf("There holds x==116\n"); } else { printf("Surprise, surprise!\n"); } } Datentyp float double ◮ Output: x=116.000000 floor(x)=115.000000 Surprise, surprise! 100 printf %f %f scanf %f %ℓf 101