Informatik 1 (251-0832-00) D

Werbung
Informatik 1 (251-0832-00)
D-MAVT
F2010
Operatoren,
Auswertungsreihenfolge,
Fliesskommazahlen
Yves Brise
20100310 - Übungsstunde 2
Kommandozeile (UNIX)
Textbasiertes “Fenster”
zu den Innereien ihres
Computers
Siehe
unix_intro.pdf
• Manuelles Compilieren von Programmen
• Aufrufen von Programmen
• Dateiverwaltung cd, ls, mv, cp, g++
• Unter Windows: cmd.exe
Yves Brise
20100310 - Übungsstunde 2
Inhalt
Ziele:
• Beherschen aller Operatoren
• Richtiger Umgang mit Fliesskommazahlen
Heute nicht (siehe Vorlesung):
• Character processing, ASCII
• Konstanten
• Gültigkeitsbereiche (Scopes)
• Funktionen
Yves Brise
20100310 - Übungsstunde 2
rvalues und lvalues
Definition
Ein lvalue ist ein Ausdruck, der eine Adresse hat (z.B.Variable).
Alles andere sind rvalues (z.B. Literal).
• Die Bezeichnungen kommen daher, dass nur ein Ausdruck
mit Adresse auf der linken Seite einer Zuweisung stehen darf
(vgl. left und right)
• Operatoren definieren, ob sie einen lvalue brauchen oder
nicht.
• Ein lvalue kann problemlos in einen rvalue konvertiert
werden. Es wird einfach der Wert and der Adresse des lvalue
geholt.
Yves Brise
20100310 - Übungsstunde 2
Zuweisungsoperator
lvalue
int a;
a = 1;
Zuweisungsoperator
rvalue
Zuweisung ist rechts-assoziativ und gibt einen lvalue zurück,
Bsp. a = b = 1
a = (b = 1)
Es gibt noch die Varianten += -= *= /= %= =,
Bsp. a += 1
a = a + 1
Single Modification Rule
Eine Variable darf in einem Ausdruck nur einmal verändert
werden, z.B. x = ++x + 1 ist nicht gut.
Yves Brise
20100310 - Übungsstunde 2
Inkrement und Dekrement
int a = 1;
++a; a--;
Prefix Inkrement
Postfix Dekrement
• Der Effekt von Inkrement ist, dass er die Variable um eins
erhöht, Dekrement erniedrigt die Variable um eins.
• Prefix: lvalue → lvalue, gibt neuen Wert zurück.
• Postfix: lvalue → rvalue, gibt alten Wert zurück.
• Die Prefix Form ist effizienter.
• Gibt es nicht nur für int. Besonders interessant auch für
eigene Datentypen (Klassen) via Overloading und für Iteratoren.
Yves Brise
20100310 - Übungsstunde 2
Relationale Operatoren
Damit können Vergleiche angestellt werden. Die Operanden
sind zwei rvalues des selben Typs, die Rückgabe ist ein bool.
Die Operatoren sind
== != < <= > >=
Regel:
• Relationale Operatoren binden
schwächer als aritmethische
und stärker als logische.
• Sind links-assoziativ,
Bsp. a < b == c
(a < b)== c
Yves Brise
if (a >= 0) {
...
} else if (a == 1) {
...
} else {
...
}
20100310 - Übungsstunde 2
Logische Operatoren
Operieren auf Wahrheitswerten (bool).
Wir benötigen UND (&&) und ODER (||) und nicht (!).
Regel:
! bindet stärker als &&, stärker als ||
Bsp: a&&!b||c
(a&&(!b))||c
&&
true false
true true false
false false false
true false
true true true
false true false
||
Short-circuit Evaluation
Ausdrücke werden von links nach rechts
ausgewertet. Wenn schon klar ist, wie der
Wert des gesamten Ausdrucks ist, wird der
zweite Operand nicht mehr ausgewertet.
Bsp. p!=0 && p->a > 0
Yves Brise
!
20100310 - Übungsstunde 2
true false
false true
Die ganze Wahrheit über Operatoren
Präzedenz
Operator
Stelligkeit
Assoziativität
r/l-value
2
++ -- (postfix)
1
links
l→r
2
3
3
3
3
5
6
8
9
13
14
16
static_cast
++ -- (prefix)
+!
(type)
*/%
+< <= > >=
!= ==
&&
||
+= -= *= /= %= =
1
1
1
1
1
2
2
2
2
2
2
2
links
rechts
rechts
rechts
rechts
links
links
links
links
links
links
rechts
r→r
l→l
r→r
r→r
r→r
rxr→r
rxr→r
rxr→r
rxr→r
rxr→r
rxr→r
lxr→l
http://en.wikipedia.org/wiki/Operators_in_C_and_C++#Operator_precedence
Yves Brise
20100310 - Übungsstunde 2
Auswertungsreihenfolge
Klammerung ergibt Ausdrucksbaum:
9
*
celsius
/
5
+
32
<=
32
+
(((9 * celsius) / 5) + 32) <= (32 + o)
Yves Brise
20100310 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
/
5
+
32
<=
32
+
(((9 * celsius) / 5) + 32) <= (32 + o)
Yves Brise
20100310 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
/
5
+
32
<=
32
+
(((9 * celsius) / 5) + 32) <= (32 + o)
Yves Brise
20100310 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
(((9 *
10.0
/
5
+
32
<=
32
+
) / 5) + 32) <= (32 + o)
Yves Brise
20100310 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
(((9 *
10.0
/
5
+
32
<=
32
+
) / 5) + 32) <= (32 + 0)
Yves Brise
20100310 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
((
*
celsius
90.0
/
5
+
32
<=
32
+
/ 5) + 32) <= (32 + 0)
Yves Brise
20100310 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
((
*
celsius
90.0
/
5
+
32
<=
32
/ 5) + 32) <=
Yves Brise
20100310 - Übungsstunde 2
32
+
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
(
*
celsius
/
5
18.0
+
32
<=
32
+ 32) <=
Yves Brise
20100310 - Übungsstunde 2
32
+
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
/
5
+
50.0
Yves Brise
32
<=
32
<=
20100310 - Übungsstunde 2
32
+
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
/
5
+
32
<=
32
false
Yves Brise
20100310 - Übungsstunde 2
+
o
Auswertungsreihenfolge
Gültige Reihenfolge: Jeder Knoten wird erst nach seinen
Kindern ausgewertet.
Kinder
Knoten
Vorsicht: Die Reihenfolge ist nicht immer eindeutig bestimmt.
Besonders relevant bei “effektvollen” Operatoren.
Bsp. x++ + x → 2x oder 2x+1?
“Guter” Ausdruck: Jede gültige Reihenfolge führt zum selben
Ergebnis.
Yves Brise
20100310 - Übungsstunde 2
Schnellübung
Klammern & Auswerten! Typ, Wert?
int a(2), b(0);
float s(1.5f);
bool t(true), f(false);
a)
b)
c)
d)
e)
f)
g)
h)
i)
j)
k)
l)
t = a - 1 < b
t || s > 0 && f
1 + 1 * 6 / 4 == 3 && 2.1 / 1.3 < 1.8
12 / 6 / 2 * 3.0 + 1 < 4 || 2.0 * 2 > 1
11 * 19 % 21 * 13 % 23 * 3 % 3
(++a - 1) / 2
a++ - 1 / 2
a != 2 && a - 1 != 1 || a + 1 == 3
17 / 2 == 8.5 && 7 * 3 == 21.0
s = a = 4 / 5
t || 127.37 * s && b == 0
int(8.5) - int(7.6) / ++ b
Yves Brise
20100310 - Übungsstunde 2
Schnellübung
Lösung
int a(2), b(0);
float s(1.5f);
bool t(true), f(false);
a)
b)
c)
d)
e)
f)
g)
h)
i)
j)
k)
l)
t=((a-1)<b); // bool, false
t||((s>0)&&f); // bool, true
((1+((1*6)/4)))==3)&&((2.1/1.3)<1.8); // bool, false
(((((12/6)/2)*3.0)+1)<4)||((2.0*2)>1); // bool, true
(((((11*19)%21)*13)%23)*3)%3; // int, 0
((++a)-1)/2; // int, 1
(a++)-(1/2); // int, 2
((a!=2)&&((a-1)!=1))||((a+1)==3); // bool, true
((17/2)==8.5)&&((7*3)==21.0); // bool, false
s=(a=(4/5)); // float, 0.0f
t||(((127.37*s)&&b)==0); // bool, true
int(8.5)-(int(7.6)/(++b)); // int, 1
Yves Brise
20100310 - Übungsstunde 2
IEEE754, float, double
float:
double:
(−1)V · 2E −127 · (1.M)
V
E −1023
(−1) · 2
Yves Brise
· (1.M)
20100310 - Übungsstunde 2
Rechnen mit Fliesskommazahlen
Approximation der Euler-Konstante
∞
�
1
e=
i!
i=0
// Program: euler.cpp
// Approximate Euler's constant e.
#include <iostream>
std::cout.precision(10);
int main ()
{
// values for term i, initialized for i = 0
float t = 1.0f;
// 1/i!
float e = 1.0f;
// i-th approximation of e
std::cout << "Approximating the Euler constant...\n";
// steps 1,...,n
for (unsigned int i = 1; i < 10; ++i) {
e += t /= i;
// compact form of t = t / i; e = e + t
std::cout << "Value after term " << i << ": " << e << "\n";
}
return 0;
}
Richtig e=2,718281828459...
Yves Brise
20100310 - Übungsstunde 2
Löcher im Wertebereich
// Program: diff.cpp
// Check subtraction of two floating point numbers
#include <iostream>
int main()
{
// Input
float n1;
std::cout << "First number
std::cin >> n1;
float n2;
std::cout << "Second number
std::cin >> n2;
=? ";
Eingabe: 1.5
=? ";
Eingabe: 1.0
Beispiel diff.cpp
float d;
std::cout << "Their difference =? ";
std::cin >> d;
Eingabe: 0.5
// Computation and output
std::cout << "Computed difference - input difference = "
<< n1 - n2 - d << ".\n";
return 0;
Ausgabe: 0
}
Yves Brise
20100310 - Übungsstunde 2
Löcher im Wertebereich
// Program: diff.cpp
// Check subtraction of two floating point numbers
#include <iostream>
int main()
{
// Input
float n1;
std::cout << "First number
std::cin >> n1;
float n2;
std::cout << "Second number
std::cin >> n2;
=? ";
Eingabe: 1.1
=? ";
Eingabe: 1.0
Beispiel diff.cpp
float d;
std::cout << "Their difference =? ";
std::cin >> d;
Eingabe: 0.1
// Computation and output
std::cout << "Computed difference - input difference = "
<< n1 - n2 - d << ".\n";
return 0;
}
Yves Brise
Ausgabe:
2.23517e-08
20100310 - Übungsstunde 2
IEEE754, Goldene Regel 1
Regel 1:
Teste keine Fliesskommazahlen auf
Gleichheit, wenn mindestens eine das
Ergebnis einer Rundungsoperation ist.
for (float i = 0.1; i != 1.0; i += 0.1){
std::cout << i << “\n”;
}
Klingt theoretisch gut, aber in der Praxis Endlosschleife,
da
(0.1) =
ˆ (0.00011)
dez
Yves Brise
bin
20100310 - Übungsstunde 2
IEEE754, Goldene Regel 2
Regel 2:
Vermeide die Addition von Zahlen sehr
unterschiedlicher Grösse.
Beispiel Harmonische Zahl
n
�
1
lim Hn ≈ ln n
Hn =
n→∞
i
i=1
Berechnung vorwärts:
Berechnung rückwärts:
Siehe harmonic.cpp ...
1 1
1
Hn = 1 + + + ... +
2 3
n
1
1
Hn = +
+ ... + 1
n n−1
Yves Brise
20100310 - Übungsstunde 2
IEEE754, Goldene Regel 3, Auslöschung
Regel 3:
Vermeide die Subtraktion von Zahlen
sehr ähnlicher Grösse.
Bsp. Berechnung der Diskriminante einer quadratischen
�
Gleichung:
b 2 − 4ac
Problem: Die involvierten Zahlen können das Ergebins
einer Rundungsoperation sein. Die Subtraktion kann den
Fehler von wenig signifikanten Bits zu signifikatnen Bits
erheben. Resultat kann fälschlicherweise 0 sein.
Stichwort: Auslöschung, Cancellation
Yves Brise
20100310 - Übungsstunde 2
Excel 2007 Bug
Excel sagt:
77.1 · 850 = 100000
Richtiges Resultat: 77.1 · 850 = 65535
?
Eigentlich nur Anzeigefehler: Eine von zwölf (laut Micorsoft)
Zahlen nahe an 65535, die falsch ins Dezimalsystem
umgewandelt werden. Intern wird richtig weiter gerechnet.
Aber: Die zugrunde liegende Ursache ist natürlich, dass die
Berechnung mit Fliesskommazahlen nicht exakt
durchführbar ist.
Yves Brise
20100310 - Übungsstunde 2
string vs. std::cin
Problem:
Es wird nicht genügend
Speicher alloziert.
#include <iostream>
#include <string>
int main() {
string s;
std::cin >> s;
}
string s(“abcdef...”);
string s(10,’0’);
std::cout << s.capacity();
s.reserve(10);
Yves Brise
20100310 - Übungsstunde 2
GOTO
label1:
// do something
goto label2;
// do something
label2:
// do something
goto label1;
Wird nicht mehr oft
verwendet, da ein
übermässiger Gebrauch zu
schwierig zu lesendem
Code führt, sog. SpaghettiCode.Verhalten kann
immer auch mit anderen
Kontrollstrukturen erreicht
werden.
Edsger Dijkstra: “A Case Against the Go To Statement”,
wurde 1968 als “The Go To Statement Considered
Harmful” veröffentlicht.
Yves Brise
20100310 - Übungsstunde 2
Tipps zur Serie 2
Aufgaben 1, 2 und 3: Siehe Schnellübungen.
Aufgaben 4: Schritt für Schritt durchgehen und
von Hand ausrechnen.
Aufgaben 5: Einlesen von 4 Werten (std::cin) und
dann einfache Berechnung mit Ausgabe.
Versuchen Sie, das Programm selbsterklärend zu
machen, d.h. sinnvolle Anfragen an den Benutzer
zu stellen.
Yves Brise
20100310 - Übungsstunde 2
Zugehörige Unterlagen
Herunterladen