Überprüfen von Gleichungen
-
Hallo!
Es geht um die Aufgabe 22 auf diesem Blatt: http://www.itp.uni-hannover.de/~dragon/blatt05.pdf bzw. http://www.itp.uni-hannover.de/~dragon/blatt05.ps
Meine Lösung dazu lautet:
// Uebungsblatt: 5 // Aufgabe: 22 // // Funktion: Ueberprueft diverse Gleichungen // Autor: <Realname zensiert>, <Immatrikulationsnummer zensiert> // // Ausgabe: // Nr. 1: OK // Nr. 2: OK // Nr. 3: OK // Nr. 4: OK #include <iostream> #include <string> #include <sstream> using namespace std; int delta(int i, int j) { if (i == j) return 1; else return 0; } int epsilon(int i, int j, int k) { if ((i == 1 && j == 2 && k == 3) || (i == 3 && j == 1 && k == 2) || (i == 2 && j == 3 && k == 1)) return 1; else if ((i == 3 && j == 2 && k == 1) || (i == 1 && j == 3 && k == 2) || (i == 2 && j == 1 && k == 3)) return -1; else return 0; } struct result { bool ok; string errmsg; }; result f1(void) { result r; for (int i = 1; i < 4; i++) for (int j = 1; j < 4; j++) for (int k = 1; k < 4; k++) for (int l = 1; l < 4; l++) for (int m = 1; m < 4; m++) for (int n = 1; n < 4; n++) if (!(epsilon(i, j, k) * epsilon(l, m, n) == delta(i, l) * delta(j, m) * delta(k, n) + delta(j, l) * delta(k, m) * delta(i, n) + delta(k, l) * delta(i, m) * delta(j, n) - delta(j, l) * delta(i, m) * delta(k, n) - delta(i, l) * delta(k, m) * delta(j, n) - delta(k, l) * delta(j, m) * delta(i, n))) { r.ok = false; stringstream ss; ss << "e" << i << j << k << "*e" << l << m << n << " = d" << i << l << "*d" << j << m << "*d" << k << n << " + d" << j << l << "*d" << k << m << "*d" << i << n << " + d" << k << l << "*d" << i << m << "*d" << j << n << " - d" << i << l << "*d" << j << m << "*d" << k << n << " - d" << j << l << "*d" << k << m << "*d" << i << n << " - d" << k << l << "*d" << i << m << "*d" << j << n; r.errmsg = ss.str(); return r; } r.ok = true; return r; } result f2(void) { result r; for (int i = 1; i < 4 ; i++) for (int j = 1; j < 4 ; j++) for (int l = 1; l < 4 ; l++) for (int m = 1; m < 4 ; m++) { int sum = 0; for (int k = 1; k < 4; k++) sum += epsilon(i, j, k) * epsilon(l, m, k); if (!(sum == delta(i, l) * delta(j, m) - delta(j, l) * delta(i, m))) { r.ok = false; stringstream ss; ss << "e" << i << j << "k*e" << l << m << "k = d" << i << l << "*d" << j << m << " - d" << j << l << " *d" << i << m; r.errmsg = ss.str(); return r; } } r.ok = true; return r; } result f3(void) { result r; for (int i = 1; i < 4 ; i++) for (int l = 1; l < 4 ; l++) { int sum = 0; for(int j = 1; j < 4; j++) for(int k = 1; k < 4; k++) sum += epsilon(i, j, k) * epsilon(l, j, k); if (!(sum == 2 * delta(i, l))) { r.ok = false; stringstream ss; ss << "e" << i << "jk*e" << l << "jk = 2*d" << i << l; r.errmsg = ss.str(); return r; } } r.ok = true; return r; } result f4(void) { result r; int sum = 0; for (int i = 1; i < 4 ; i++) for (int j = 1; j < 4 ; j++) for (int k = 1; k < 4 ; k++) sum += epsilon(i, j, k) * epsilon(i, j, k); if (sum != 6) { r.ok = false; stringstream ss; ss << "eijk*eijk = " << sum; r.errmsg = ss.str(); } else r.ok = true; return r; } int main(int argc, char argv[]) { cout << "Nr. 1: "; if (f1().ok) cout << "OK" << endl; else cout << "Failed at: " << f1().errmsg << endl; cout << "Nr. 2: "; if (f2().ok) cout << "OK" << endl; else cout << "Failed at: " << f2().errmsg << endl; cout << "Nr. 3: "; if (f3().ok) cout << "OK" << endl; else cout << "Failed at: " << f3().errmsg << endl; cout << "Nr. 4: "; if (f4().ok) cout << "OK" << endl; else cout << "Failed at: " << f4().errmsg << endl; return 0; }Was haltet ihr davon?
Ich bitte um jede Art von Kritik.MfG
mastercppPS: Ist schon abgegeben. (Ihr macht also nicht meine Hausaufgaben)
EDIT: Ups, falsche Nummer
-
Ich würde das Ergebnis der jeweiligen Teilfunktionen zwischenspeichern:
result res; res=f1(); if(res.ok) cout << "OK" << endl; else cout << "Failed at: " << res.errmsg << endl;(mit deinem Quelltext rechnest du die ganze Schleifenserie im Ernstfall doppelt durch - erst um das .ok zu ermitteln, danach um nochmal die Fehlerstelle zu finden)
-
Hallo mastercpp,
es gibt ein paar kosmetische Sachen. Bei den operator++ bevorzugt man eher den prefix- statt postfix-operator. Bei int's ist es aber egal; dann ist es eher eine Stilfrage.
Die Schreibweise func(void), wenn eine Funktion keine Parameter hat, ist eher C-Stil. void kann man weglassen.
Wichtiger finde ich, die Schreibweise des Programms so umzustellen, dass Tipp-Fehler möglichst offensichtlich werden. Bei dieser Art von Programmm können kleinere Schreibfehler zum Problem werden.
Zum Beispiel in f1():if (!(epsilon(i, j, k) * epsilon(l, m, n) == delta(i, l) * delta(j, m) * delta(k, n) + delta(j, l) * delta(k, m) * delta(i, n) + delta(k, l) * delta(i, m) * delta(j, n) - delta(k, l) * delta(j, m) * delta(i, n) // <-- - delta(j, l) * delta(i, m) * delta(k, n) - delta(i, l) * delta(k, m) * delta(j, n) ))ich habe lediglich die letzte Zeile (s. Markierung) der Gleichung um zwei Zeilen nach oben geschoben. Das ändert natürlich nichts an dem Programm, aber es wird eine Struktur bei der Indizierung sichtbar.
In den unteren drei Zeilen laufen die drei Indizes genau entgegengesetzt zu den oberen drei Zeilen. Durch eine solche Anordnung würde ein Tippfehler eher auffallen, ohne dass man die Gleichung genau kennen muss!Noch ein Punkt ist redundanter Code. Grundsätzlich gilt es den zu verhindern. Zum einen könntest Du die result-struct so erweitern
struct result { result() : ok( true ), errmsg() {} explicit result( const std::string& em ) : ok( false ), errmsg( em ) {} bool ok; string errmsg; };und könntest dann in jeder Funktion die immer gleichen vier Zeilen einsparen. Also z.B. in f1()
result f3(void) { // result r; for (int i = 1; i < 4 ; i++) for (int l = 1; l < 4 ; l++) { int sum = 0; for(int j = 1; j < 4; j++) for(int k = 1; k < 4; k++) sum += epsilon(i, j, k) * epsilon(l, j, k); if (!(sum == 2 * delta(i, l))) { // r.ok = false; stringstream ss; ss << "e" << i << "jk*e" << l << "jk = 2*d" << i << l; // r.errmsg = ss.str(); return result( ss.str() ); } } // r.ok = true; return result(); }alle auskommentierten Zeilen fallen jeweils weg.
Redundant sind auch die vielen Schleifen; wobei es hier schwieriger ist, dass zu generalisieren. Eine Möglichkeit wäre so was
template< int Von, int Bis, int N > struct Indizes { Indizes() : m_idx( N, Von ), m_end( false ) {} Indizes& operator++() { int n_overflow = 0; for( std::vector< int >::iterator i = m_idx.begin() ; i != m_idx.end() && ++*i > Bis; ++i ) { *i = Von; ++n_overflow; } if( n_overflow == N ) m_end = true; return *this; } int operator[]( int i ) const { return m_idx[i]; } bool end() const { return m_end; } private: std::vector< int > m_idx; bool m_end; };und die Anwendung
result f1(void) { for( Indizes< 1, 3, 6 > i; !i.end(); ++i ) { if( !... ) // Zugriff mit i[<Idx des Index>] { ... return result( ss.str() ); } } return result(); }ob man das dann macht oder nicht, ist aber eine Geschmacksfrage

Gruß
Werner