anwenden:ganzzahl_test
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
— | anwenden:ganzzahl_test [2020-05-14 15:03] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | ====== Ganzzahl_Test : Testprogramme für beliebig genaue Ganzzahlen ====== | ||
+ | > Dies ist zugleich eine Gelegenheit für dich, durch ein eklatantes Scheitern die Tugend der Bescheidenheit zu lernen, welche - in deinem jungen Alter vielleicht verzeihlicherweise noch kaum entwickelt ist - eine unabdingbare Voraussetzung für dein späteres Fortkommen als Mitglied deiner Zunft und deines Standes, als Ehemann, als Untertan, als Mensch und als ein guter Christ sein wird. | ||
+ | >> | ||
+ | |||
+ | |||
+ | Dies ist ein Demo- und Testprogramm für Ganzzahlimplementierungen. | ||
+ | |||
+ | <code cpp> | ||
+ | //: ganzzahl_test.cpp : Tests Ganzzahlbibliothek - R.Richter 2004-10-21 | ||
+ | /////////////////////////////////////////////////////////////////////// | ||
+ | |||
+ | #include < | ||
+ | #include " | ||
+ | using namespace std; | ||
+ | |||
+ | const long BASIS = 1L << 16; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Die ersten Tests erfordern keine Eingabefunktionen. | ||
+ | Hier geht es um Prüfungen, | ||
+ | ob die Grundoperationen mathematisch richtig implementiert sind. | ||
+ | Insbesondere die 3. binomische Formel ist ein hilfsreiches Instrument. | ||
+ | |||
+ | <code cpp> | ||
+ | void test_arithmetik() | ||
+ | { | ||
+ | Ganzzahl zero, one; | ||
+ | ++one; | ||
+ | cout << " | ||
+ | cout << "Null == " << zero << endl; | ||
+ | cout << "Eins == " << one << endl; | ||
+ | |||
+ | Ganzzahl n; | ||
+ | unsigned i; | ||
+ | for (i=0; i<BASIS; ++i) | ||
+ | { | ||
+ | ++n; | ||
+ | } | ||
+ | |||
+ | Ganzzahl base = n; | ||
+ | cout << BASIS-1 << " == " << (n-one) << endl; | ||
+ | cout << | ||
+ | cout << 2*BASIS << " == " << (n+n) << endl; | ||
+ | cout << 3*BASIS << " == " << (n+n+n) << endl; | ||
+ | |||
+ | for (i=1; i<BASIS; ++i) | ||
+ | { | ||
+ | n += base; | ||
+ | } | ||
+ | cout << BASIS << "^2-1 == " << (n-one) << endl; | ||
+ | cout << BASIS << "^2 == " << n << endl; | ||
+ | cout << BASIS << "^4 == " << n * n << endl; | ||
+ | |||
+ | cout << " | ||
+ | cout << BASIS << "^2/2 == " << n/(one+one) << endl; | ||
+ | // (n-1)(n+1) == n^2 - 1 | ||
+ | cout << BASIS << " | ||
+ | cout << BASIS << " | ||
+ | |||
+ | cout << BASIS << "^4/2 == " << n*n/ | ||
+ | // (n-1)(n^3+n^2+n+1) = n^4 - 1 | ||
+ | cout << BASIS << " | ||
+ | cout << BASIS << " | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | Konversionen aus Ganzzahlen und Zeichenketten und umgekehrt müssen korrekt sein. | ||
+ | |||
+ | <code cpp> | ||
+ | void test_konversion() | ||
+ | { | ||
+ | cout << " | ||
+ | int izahl = 1 << 31; | ||
+ | Ganzzahl zahl_aus_int = izahl; | ||
+ | cout << izahl << " == " << zahl_aus_int; | ||
+ | cout << " == " << zahl_aus_int.to_long() << endl; | ||
+ | |||
+ | std::string s = " | ||
+ | Ganzzahl zahl_aus_string = s; | ||
+ | cout << s << " == " << zahl_aus_string; | ||
+ | cout << " == " << zahl_aus_string.to_long() << endl; | ||
+ | | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | Bei logischen Tests muss statt '' | ||
+ | leider ein " | ||
+ | Automatische Rückkonvertierungen in Grundtypen | ||
+ | '' | ||
+ | würden an anderen Stellen zu Mehrdeutigkeiten führen. | ||
+ | Deshalb wurden diese nicht implementiert. | ||
+ | Wegen besserer Lesbarkeit ist ohnehin '' | ||
+ | |||
+ | <code cpp> | ||
+ | void test_vergleich() | ||
+ | { | ||
+ | Ganzzahl m(" | ||
+ | |||
+ | if (!m || !!n) | ||
+ | { | ||
+ | throw std:: | ||
+ | } | ||
+ | if (n != std:: | ||
+ | { | ||
+ | throw std:: | ||
+ | } | ||
+ | if (m != 123) | ||
+ | { | ||
+ | throw std:: | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | Hier können Benutzereingaben getestet werden. | ||
+ | |||
+ | <code cpp> | ||
+ | void test_eingabe_grundrechenarten() | ||
+ | { | ||
+ | cout << " | ||
+ | Ganzzahl eingabe1, eingabe2; | ||
+ | cin >> eingabe1 >> eingabe2; | ||
+ | cout << " | ||
+ | cout << eingabe1 << endl << eingabe2 << endl; | ||
+ | cout << "+ : " << eingabe1 + eingabe2 << endl; | ||
+ | cout << "- : " << eingabe1 - eingabe2 << endl; | ||
+ | cout << "* : " << eingabe1 * eingabe2 << endl; | ||
+ | cout << "/ : " << eingabe1 / eingabe2 << endl; | ||
+ | cout << "% : " << eingabe1 % eingabe2 << endl; | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | Ein zentraler, wichtiger Test ist die Überprüfung der Divisionsoperation. | ||
+ | Da der [[anwenden: | ||
+ | alles andere als trivial ist, | ||
+ | muss er besonders intensiv getestet werden. | ||
+ | Mit zufällig gewählten Operanden wird die Division mit Probe durchgeführt. | ||
+ | |||
+ | <code cpp> | ||
+ | #include < | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | |||
+ | string zufall() | ||
+ | { | ||
+ | char buf[20]; | ||
+ | int x = rand(); | ||
+ | if (RAND_MAX < 100000) // schlechter Zufallsgenerator | ||
+ | { | ||
+ | x *= rand(); | ||
+ | } | ||
+ | sprintf(buf, | ||
+ | return buf; | ||
+ | } | ||
+ | |||
+ | void test_dividieren(int anzahl) | ||
+ | { | ||
+ | int seed(time(NULL)); | ||
+ | srand(seed); | ||
+ | cout << " | ||
+ | " | ||
+ | cout << " | ||
+ | |||
+ | for (int i=0; i< | ||
+ | { | ||
+ | string a_strg = zufall(); | ||
+ | if (a_strg != " | ||
+ | { | ||
+ | a_strg += zufall() + zufall() + zufall(); // bis zu 40 Stellen | ||
+ | } | ||
+ | string b_strg = zufall(); | ||
+ | while (b_strg == " | ||
+ | { | ||
+ | b_strg = zufall(); | ||
+ | } | ||
+ | b_strg += zufall(); // bis zu 20 Stellen | ||
+ | |||
+ | Ganzzahl a = a_strg; | ||
+ | Ganzzahl b = b_strg; | ||
+ | Ganzzahl q = a / b; | ||
+ | Ganzzahl r = a % b; | ||
+ | // cout << a << "/" | ||
+ | // cout << a << " | ||
+ | Ganzzahl probe = q * b + r; | ||
+ | // cout << " | ||
+ | if (a != probe) | ||
+ | { | ||
+ | cout << a << "/" | ||
+ | cout << a << " | ||
+ | cout << " | ||
+ | throw std:: | ||
+ | } | ||
+ | } | ||
+ | cout << anzahl << " Tests bestanden." | ||
+ | cout << time(0) - seed << " Sekunden." | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | Hier nun der Testtreiber. | ||
+ | |||
+ | <code cpp> | ||
+ | int main() | ||
+ | { | ||
+ | try | ||
+ | { | ||
+ | test_arithmetik(); | ||
+ | test_konversion(); | ||
+ | test_vergleich(); | ||
+ | test_eingabe_grundrechenarten(); | ||
+ | test_dividieren(1000000); | ||
+ | } | ||
+ | catch(std:: | ||
+ | { | ||
+ | cerr << s << endl; | ||
+ | } | ||
+ | catch(Ganzzahl:: | ||
+ | { | ||
+ | cerr << " | ||
+ | } | ||
+ | catch(Ganzzahl:: | ||
+ | { | ||
+ | cerr << " | ||
+ | } | ||
+ | catch(...) | ||
+ | { | ||
+ | cerr << " | ||
+ | } | ||
+ | cout << " | ||
+ | cin.sync(); | ||
+ | cin.get(); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ===== Laufzeit Ganzzahlarithmetik ===== | ||
+ | Getestet wurden mehrere Versionen, | ||
+ | |||
+ | |||
+ | * eine {{arithm.cpp|einfache}} mit dezimalen Zeichenketten und | ||
+ | * zwei referenzzählende Implementierungen zur Basis 65536, | ||
+ | * eine mit einem Vektor aus Ziffern und | ||
+ | * eine mit eigener Speicherverwaltung. | ||
+ | |||
+ | | arithm | ||
+ | | Ganzzahl2 | vector< | ||
+ | | Ganzzahl | ||
+ | |||
+ | |||
+ | Drei Compiler, | ||
+ | |||
+ | |||
+ | * MS Visual C++ 6, | ||
+ | * der in [[http:// | ||
+ | * Linux g++ 3.3.2, | ||
+ | kamen in zwei Konfigurationen | ||
+ | (nichtoptimiert / Debug, optimiert / Release) | ||
+ | zum Einsatz. | ||
+ | |||
+ | Für 1 Million Divisionen mit Probe für Zahlen der Größenordnung ca. 10^36 / 10^18 | ||
+ | benötigten die Implementierungen folgende Zeiten (in Sekunden) | ||
+ | auf einem Pentium M System 1.5 GHz: | ||
+ | |||
+ | |||
+ | | Compiler | ||
+ | | Dev C++ not opt. | | ||
+ | | Dev C++ optimized | 94 | | ||
+ | | MS VC++ 6 Debug | ||
+ | | MS VC++ 6 Release | 92 | | ||
+ | | Linux g++ not opt.| | ||
+ | | Linux g++ -O3 | ||
+ | |||
+ | |||
+ | Eindeutiger Gewinner ist die | ||
+ | [[anwenden: | ||
+ | Hier sind die Quelltexte: | ||
+ | |||
+ | |||
+ | * {{ganzzahl.h}} | ||
+ | * {{ganzzahl.cpp}} | ||
+ | * {{ganzzahl_test.cpp}} | ||
anwenden/ganzzahl_test.txt · Zuletzt geändert: 2020-05-14 15:03 von 127.0.0.1