Informatik 1 (251-0832-00) D

Werbung
Informatik 1 (251-0832-00)
D-MAVT
F2011
Operatoren,
Auswertungsreihenfolge,
Fliesskommazahlen
Yves Brise
20110309 - Übungsstunde 2
Inhalt
Ziele:
• Casting, Typenkonvertierung
• Mehr Operatoren
• Fliesskommazahlen
Heute nicht (siehe Vorlesung):
• Character processing, ASCII
• Konstanten
• Gültigkeitsbereiche (Scopes)
• Funktionen
Yves Brise
20110309 - Übungsstunde 2
To Be Discussed
• Updates in Ubuntu ausstellen. Gefahr des
Systemzusammenbruchs.
System→Update Manager→Settings→(Passwort eingeben:
Informatik)→Häkchen bei “Check for updates”, “Important
Security updates” und “Recommended Updates” weg.
• Probleme mit Vollbildmodus und/oder gemeinsamem
Ordner, siehe http://info1-mavt.inf.ethz.ch/
virtualbox.php
• Musterlösungen vom letzten Jahr.
Yves Brise
20110309 - Übungsstunde 2
Explizite Typenkonvertierung
Sogenannte cast expressions, übliche Schreibweise:
type(expr) oder (type)expr
Bsp:
int(9.5+0.6)
Es wird abgerundet
(double)2+1.5f
Wie unärer Operator
(double)(7/3)
Beide Klammern erlaubt
Eigentlich besser:
static_cast<int>(9.5+0.6)
Yves Brise
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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 {
...
}
20110309 - Ü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. x!=0 && 1/x > 0.5
Yves Brise
!
20110309 - Ü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
20110309 - Übungsstunde 2
Auswertungsreihenfolge
Klammerung ergibt Ausdrucksbaum:
9
*
celsius
/
5
+
32
<=
32
+
(((9 * celsius) / 5) + 32) <= (32 + o)
Yves Brise
20110309 - Übungsstunde 2
o
Auswertungsreihenfolge
Auswertung von den Blättern zur Wurzel...
9
*
celsius
/
5
+
32
<=
32
+
(((9 * 90.0
((
(
celsius)
10.0
18.0) / 5)
50.0
+ 32)false
<= (3232
+ 0)
o)
Yves Brise
20110309 - Ü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. Funktionsaufrufe: f() + g()
“Guter” Ausdruck: Jede gültige Reihenfolge führt zum selben
Ergebnis.
Yves Brise
20110309 - Ü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
20110309 - Ü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
20110309 - Übungsstunde 2
IEEE754, float, double
float:
double:
(−1)V · 2E −127 · (1.M)
V
E −1023
(−1) · 2
Yves Brise
· (1.M)
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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. Das Resultat kann um Grössenordnungen falsch
sein.
Yves Brise
20110309 - Ü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
20110309 - Ü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
20110309 - Ü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. Und: Kommentare nicht vergessen!
Yves Brise
20110309 - Übungsstunde 2
Herunterladen