Übungsabgabe
- Immer wieder werden Codes ohne Testläufe abgegeben mit dem Kommentar:
"Konnte Fehler nicht finden" oder Ähnlichem.
Genau hierfür ist u.a. das Tutorium da. Also Übungen rechtzeitig beginnen und ins Tutorium kommen bzw. den Tutoren eine Email schreiben. - Es gibt (gestaffelte) Abzüge falls Testläufe
- manipuliert wurden (d.h. nicht zum Programm passen),
- fehlen,
- unvollständig sind.
- Bei Verdacht auf Manipulation gibt es eine Rücksprache (R) mit dem jeweiligen Tutor bevor die Punkte vergeben werden. Im eigenen Interesse auf jeden Fall zur Rücksprache kommen.
Hinweise zur 3. Übung
Initialisierung
Variablen müssen vor erstmaliger Verwendung oft initialisiert werden. Beispiel:
double sum;
[...]
sum = 0.0;
for (i=0; i<n; i++)
{
sum += folge[i];
}
Je nach Compiler wird eine frisch angelegte Variable oft automatisch auf 0 gesetzt.
Die (hier fettgedruckte) Initialisierung ist aber in diesem Praktikum verpflichtend (sonst Punkteabzug).
- kann man sich nicht auf die automatische Init verlassen,
- ist das nicht Initialisieren eine schlechte Angewohnheit die später zu oft unauffindbaren Fehlern führen kann,
- ist etwa bei dem obigen Beispiel sum = 0.0; einfach ein Bestandteil des Algorithmus. Deshalb wird sum auch an genau dieser Stelle (statt oben bei der Variablenvereinbarung) auf 0.0 gesetzt.
Vereinbarung von Feldern, Feldgrenzen
Wie setzt man mathematische Vektoren (und damit Matrizen) in C++-Felder um:
Vektor xi, i=1..10
-
Möglichkeit (bevorzugt):
const int N=10;
double x[N]; // weil N Komponenten
verwende x[0] bis x[9] für x1 bis x10 (d.h. index-shift)
-
Möglichkeit:
const int N=10;
double x[N+1];
verwende x[1] bis x[10] für x1 bis x10 (d.h. kein index-shift, 0-tes Element bleibt aber ungenutzt)
Vektor xi, i=0..10
-
Einzig sinnvolle Möglichekti:
const int N=10;
double x[N+1]; // weil N+1 Komponenten
verwende x[0] bis x[10] (kein index-shift)
Verbotene Feldzugriffe
Wird über ein Feld hinaus gelesen oder geschrieben
double x[10];
[...]
x[10] = 0.9; // verbotener Schreibzugriff
[...]
cout << x[10]*x[10] - 2.0 << endl; // verbotener Lesezugriff
kann alles Mögliche an Fehlern auftreten (keine Garantie).
pow, fabs
Wenn etwas nichts mit Potenzieren zu tun hat, ist die Verwendung von pow ineffizient. Auch fabs usw. nur verwenden wenn notwendig. Beispiele:
Falsch:
double x[N];
[...]
for (i=0; i<N; i++)
{
x[i] = pow (-1.0, i+1.0) / (i+1.0);
}
Richtig:
double x[N];
double help;
[...]
help = -1.0;
for (i=0; i<N; i++)
{
x[i] = help / (i+1.0);
help = -help;
}
x = pow (fabs(y), 2);
x = fabs(y)*fabs(y);
x = y*y; // Quadrate sind immer positiv!
Hilfsfelder nur wenn unbedingt notwendig
Viele haben bei der Berechnung der Matrixnormen (Übung 3, Bsp. 2) Hilfsfelder für die Spaltensummen etc. verwendet. Es gibt aber einen Algorithmus der ohne diese auskommt (siehe Musterlösung) - in so einem Fall soll man also auch auf die Hilfsfelder verzichten.
Vergleiche von Gleitkommavariablen
Gleitkommazahlen (double, float, etc.) soll man nie auf (Un)gleichheit testen. Falls erforderlich nur mit relativen Kriterium. Beispiel:
double x;
[...]
if (x == 0) // richtig: if (fabs(x) < EPS)
{
[...]
Bei der 3. Übung, 1. Bsp, sollte der i-te Lagrange-Koeffizient berechnet werden. Hier ein logischer Fehler:
if (x[i] != x[j]) // richtig: if (i != j)