Zählschleife for

Werbung
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
Zugehörige Unterlagen
Herunterladen