Menu Close

Programmieren, Algorithmen und Datenstrukturen 2 (Praktikum 1)

Hinweise:

  • Eigenes Print für die Klassen verwenden
  • Einrücken und Stil vereinheitlichen ( am Besten Alt+Umschalt+F )
  • Helper Funktionen als Private Methoden einbauen
  • Variablen klarer und mit sprechenden Namen benennen
  • Die Menüstruktur „Interaktiv und Zufall“ als Boolean implementieren
  • Manager Klasse für die Helper Funktionen und Sammlung bauen
  • Mit Enum die Auswahl für das Menü begrenzen

Aufgabe 1:

a) Bearbeiten Sie die Klausur aus dem ersten Semester. Versuchen Sie, eine möglichst hochwertige Lösung anzufertigen, achten Sie besonders auf Qualität. Lösung:

/*
 * File:   bib.cpp
 * Author: NROGMANN
 *
 * Created on 22. März 2012, 09:17
 */

// Präprozessor-Direktiven
#include "bib.h"
#include <iostream>

// Using-Deklarationen
using std::string;
using std::cout;

// Prototypen
extern void error(string);

// Reader

Reader::Reader()
: name(), num_books(0) {

}

Reader::Reader(string s, int n)
: name(s), num_books(n) {

}

string Reader::get_name() const {
    return name;
}

void Reader::set_name(string s) {
    name = s;
}

int Reader::get_nbooks() const {
    return num_books;
}

void Reader::inc_nbooks() {
    num_books++;
}

// Book

Book::Book()
: title(), author(), on_shelf(true) {

}

Book::Book(string t, string a)
: title(t), author(a), on_shelf(true) {

}

string Book::get_title() const {
    return title;
}

string Book::get_author() const {
    return author;
}

bool Book::get_onshelf() const {
    return on_shelf;
}

void Book::set_onshelf(bool b) {
    on_shelf = b;
}

// Loan

Loan::Loan()
: sLender(), pBorrowed(0) {

}

Loan::Loan(string s, Book* b)
: sLender(s), pBorrowed(b) {

}

string Loan::get_lender() {
    return sLender;
}

Book* Loan::get_borrowed() {
    return pBorrowed;
}

void Loan::print() {
    cout << sLender << "\tleiht\t"
            << pBorrowed->get_title()
            << "("
            << pBorrowed->get_author()
            << ")"
            << std::endl;
}

/*
 * File:   bib.h
 * Author: NROGMANN
 *
 * Created on 22. März 2012, 09:17
 */

#ifndef BIB_H
#define	BIB_H

#include <string>

using std::string;

class Reader {
private:
    string name;
    int num_books;
public:
    Reader();
    Reader(string, int);
    string get_name() const;
    void set_name(string);
    int get_nbooks() const;
    void inc_nbooks();

};

class Book {
private:
    string title;
    string author;
    bool on_shelf;
public:
    Book();
    Book(string, string);
    string get_title() const;
    string get_author() const;
    bool get_onshelf() const;
    void set_onshelf(bool);
};

class Loan {
private:
    string sLender;
    Book * pBorrowed;
public:
    Loan();
    Loan(string, Book*);
    string get_lender();
    Book* get_borrowed();
    void print();
};
#endif	/* BIB_H */

/*
 * File:   error_catch.h
 * Author: NROGMANN
 *
 * Created on 22. März 2012, 09:07
 */

#ifndef ERROR_CATCH_H
#define	ERROR_CATCH_H

#include <stdexcept>
#include <string>
#include <iostream>

using std::runtime_error;
using std::out_of_range;
using std::cerr;
using std::string;

void error(string s) {
    throw runtime_error(s);
}

/*
catch( runtime_error &e ) {
                cerr << "Laufzeitfehler: " << e.what() << '\n';
                return 1;
        }
        catch( ... ) {
                cerr << "Unbekannter Ausnahmefehler" << '\n';
                return 2;
        }
 */

#endif	/* ERROR_CATCH_H */

/*
 * File:   main.cpp
 * Author: NROGMANN
 *
 * Created on 22. März 2012, 09:07
 */
// Präprozessor-Direktiven
#include <iostream>
#include <iomanip>
#include <vector>
#include "error_catch.h"
#include "bib.h"

// Using-Deklarationen
using std::vector;
using std::cout;
using std::cin;
using std::endl;

// Prototypen
void populate_books(vector<Book>&vBooks, string title, string author);
void print_books(vector<Book>&vBooks);
void populate_readers(vector<Reader>&vReaders, string name, int num);
void print_readers(vector<Reader>&vReaders);
void add_reader(vector<Reader>&vReaders);
void populate_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders, string reader, string title, string author);
void print_loans(vector<Loan>&vLoans);
void add_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders);

Reader* identify_reader(vector<Reader>&vReaders, string name);
Book* identify_book(vector<Book>&vBooks, string title, string author);

int main() {
    try {
        // Objekte anlegen
        vector<Book>vBooks;
        vector<Reader>vReaders;
        vector<Loan>vLoans;

        // Objekte füllen
        populate_books(vBooks, "Suppen", "Schlawiner");
        populate_books(vBooks, "Desserts", "Schlawiner");
        populate_books(vBooks, "C++", "Stroustrup");
        populate_books(vBooks, "C++", "Petersen");
        populate_books(vBooks, "Bergtouren", "Rittersdorf");
        populate_books(vBooks, "XML", "Manfreti");
        populate_books(vBooks, "Feuersteine", "Hibbler");
        populate_books(vBooks, "Dinosaurier", "Gould");
        populate_books(vBooks, "Pandas", "Gould");
        populate_books(vBooks, "Scherz", "Kundera");

        populate_readers(vReaders, "Barney", 0);
        populate_readers(vReaders, "Betty", 0);
        populate_readers(vReaders, "Fred", 0);
        populate_readers(vReaders, "Wilma", 0);

        // Ausgabe
        print_books(vBooks);
        print_readers(vReaders);

        // Weitere Leser hinzufügen
        add_reader(vReaders);

        // Ausleihe hinzufügen
        populate_loans(vLoans, vBooks, vReaders, "Betty", "C++", "Stroustrup");
        populate_loans(vLoans, vBooks, vReaders, "Betty", "XML", "Manfreti");
        populate_loans(vLoans, vBooks, vReaders, "Fred", "C++", "Petersen");
        populate_loans(vLoans, vBooks, vReaders, "Fred", "Feuersteine", "Hibbler");
        populate_loans(vLoans, vBooks, vReaders, "Wilma", "Bergtouren", "Rittersdorf");

        print_loans(vLoans);
        add_loans(vLoans, vBooks, vReaders);
    } catch (out_of_range &e) {
        cerr << "Out of Range: " << e.what() << '\n';
        return -1;
    } catch (runtime_error &e) {
        cerr << "Laufzeitfehler: " << e.what() << '\n';
        return -2;
    } catch (...) {
        cerr << "Unbekannter Ausnahmefehler" << '\n';
        return -3;
    }

    return 0;
}

void populate_books(vector<Book>&vBooks, string title, string author) {
    vBooks.push_back(Book(title, author));
}// populate_books

void print_books(vector<Book>&vBooks) {
    cout << "Buchliste:\n";
    cout << std::setw(15) << std::left << "Titel\t\tAutor\t\tBestand" << endl;
    for (int i = 0; i < vBooks.size(); i++) {
        cout << std::setw(15) << std::left << vBooks.at(i).get_title() << "\t"
             << std::setw(15) << std::left << vBooks.at(i).get_author() << "\t"
             << vBooks.at(i).get_onshelf() << endl;
    }
    cout << endl;
}// print_books

void populate_readers(vector<Reader>&vReaders, string name, int num) {
    vReaders.push_back(Reader(name, num));
}// populate_readers

void print_readers(vector<Reader>&vReaders) {
    cout << "Leserliste:\n";
    cout << std::setw(15) << std::left << "Name\t\tAusgeliehen" << endl;
    for (int i = 0; i < vReaders.size(); i++) {
        cout << std::setw(15) << std::left << vReaders.at(i).get_name() << "\t"
                << vReaders.at(i).get_nbooks() << endl;
    }
    cout << endl;
}// print_readers

void add_reader(vector<Reader>&vReaders) {
    bool bFinished = false;
    while (!bFinished) {
        bool bDouble = false;
        string strTemp = "";
        cout << "Weitere Leser hinzufügen (beenden mit 'q'): ";
        cin >> strTemp;

        // Prüfe, ob Eingabe gültig
        if (!cin)
            error("Fehlerhafte Eingabe");
        if (cin.peek() == EOF)
            error("End of File..");
        // Schleifenabbruch
        if (strTemp == "q") {
            bFinished = true;
            break;
        }
        // Check, ob neuer Leser schon in Leserliste
        for (int i = 0; i < vReaders.size(); i++) {
            if (strTemp == vReaders.at(i).get_name()) {
                bDouble = true;
                break;
            }
        } // for

        // Wenn Name nicht vorhanden
        if (!bDouble) {
            // Leser hinzufügen
            populate_readers(vReaders, strTemp, 0);
            cout << "Leser " << strTemp << " hinzugefügt\n";
            print_readers(vReaders);
        } else {
            cout << "Fehler: Leser schon vorhanden!\n";
        }
    }// while
    cout << endl;
}// add_reader

void populate_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders, string name, string title, string author) {
    Reader* pReader = identify_reader(vReaders, name);
    Book* pBook = identify_book(vBooks, title, author);
    if (pReader != 0 && pBook != 0) {
        vLoans.push_back(Loan(name, pBook));
        pReader->inc_nbooks();
        pBook->set_onshelf(false);
    } else {
        error("Buch oder Leser nicht vorhanden!");
    }
}// populate_loans

void print_loans(vector<Loan>&vLoans) {
    cout << "Ausleihe:\n";
    for (int i = 0; i < vLoans.size(); i++)
        vLoans.at(i).print();
}// print_loans

void add_loans(vector<Loan>&vLoans, vector<Book>&vBooks, vector<Reader>&vReaders) {
    bool bFinished = false;
    while (!bFinished) {
        string strReader = "";
        string strBook = "";
        string strAuthor = "";

        cout << "\nWeitere Ausleihen hinzufügen (beenden mit 'q')\n"
                << "('Leser' 'Buch' 'Author'): ";
        cin >> strReader;
        if (!cin)
            error("Fehlerhafte Eingabe");
        if (cin.peek() == EOF)
            error("End of File..");
        if (strReader == "q") {
            bFinished = true;
            break;
        }
        cin >> strBook >> strAuthor;
        if (!cin)
            error("Fehlerhafte Eingabe");
        if (cin.peek() == EOF)
            error("End of File..");

        // Prüfe, ob Buch schon ausgeliehen
        Book* pBook = identify_book(vBooks, strBook, strAuthor);
        if (pBook == 0) {
            error("Buch nicht vorhanden");
        } else {
            if (pBook->get_onshelf() == false) {
                cout << "Buch schon ausgeliehen\n";
                continue;
            }
        }

        // Prüfe, ob Leser "registriert"
        Reader* pReader = identify_reader(vReaders, strReader);
        if (pReader == 0) {
            cout << "Fehler: Benutzer nicht registriert\n";
        } else {
            populate_loans(vLoans, vBooks, vReaders, strReader, strBook, strAuthor);
            cout << endl;
            print_readers(vReaders);
            print_books(vBooks);
            print_loans(vLoans);
            cout << "\nBuch erfolgreich ausgeliehen\n";
        }
    }// while
}// add_loans

Reader* identify_reader(vector<Reader>&vReaders, string name) {
    // Leserobjekt identifizieren
    for (int j = 0; j < vReaders.size(); j++) {
        if (vReaders.at(j).get_name() == name) {
            return &vReaders.at(j);
        }
    }
    return 0;
}// identify_reader

Book* identify_book(vector<Book>&vBooks, string title, string author) {
    // Buch eindeutig identifizieren
    for (int i = 0; i < vBooks.size(); i++) {
        if (vBooks.at(i).get_title() == title) {
            if (vBooks.at(i).get_author() == author) {
                return &vBooks.at(i);
            }
        }
    }
    return 0;
}// identify_book

b) Formulieren Sie ein eigenes Beispiel für eine entsprechende Aufgabenstellung, die zukünftig als Klausur dienen könnte. 

Aufgabe 2

a) Entwerfen und implementieren Sie eine Klasse namens NPV (net present value) für die Berechnung des Kapitalwerts C0 einer Zahlungsreihe, wobei das Endergebnis der Berechnung unter Berücksichtigung der 4/5-Rundung auf Hundertstel („zwei Stellen nach dem Komma“) genau sein soll. Sehen Sie für die Zahlungsreihe eine vector<long int> Membervariable namens inv (investment) in Hundertstel der Währung vor (lassen Sie die Denomination der Währung unbestimmt). Sehen Sie für den Kalkulationszinssatz eine double Membervariable namens irate (interest rate) vor, die auf vier Stellen nach dem Komma genau ist, also z.B. 0.0412 bei 4,12% pro Jahr. Gehen Sie von einem einzigen Zinssatz für die ganze Zahlungsreihe aus. Der t-te Wert in inv, d.h. also inv.at(t), steht damit für die saldierten monetären  Zuflüsse (positiver Wert) bzw. Abflüsse (negativer Wert) im t-ten Jahr. Zur Abzinsung des t-ten Werts auf die Gegenwart dividieren Sie ihn durch (1 + irate )t . Der Kapitalwert C0 ist die Summe aller derart abgezinsten Werte aus inv.

Sehen Sie auch Konstruktoren vor, die zufällige Zahlungsreihen und Zinssätze erzeugen, um Ihnen beim Testen zu helfen.  

/*
 * File:   error.h
 * Author: maximilian.krieg
 *
 * Created on 26. März 2012, 13:53
 */

#ifndef ERROR_H
#define    ERROR_H

#include <iostream>
#include <stdexcept>
using std::string;
using std::runtime_error;

inline void error(string s) {
    throw runtime_error(s);
}

inline void error(string s1, string s2) {
    error(s1 + s2);
}

#endif    /* ERROR_H */
#ifndef NPV_H
#define    NPV_H
#include <math.h>
#include <vector>
#include "error.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

using namespace std;

//Defitionen: Klassen 
class npv;

//Definitionen: Support - Funktionen -
double nachkommastelle(double, int);
double interestrate(double);
void ausgabe(const vector<npv>&, int);
void anlegen(vector<npv>&, int);

// Net-Present-Value-Klasse (Berechnung von Kapitalwert einer Zahlungsreihe) -
class npv {                                    
public:

    // Konstruktoren
    npv(); // Standardkonstruktor
    npv(vector<long int>, double); // Definierte Zahlungsreihe mit fester Rate
    npv(int);

    // Methoden zur Interest Rate
    double set_irate(double); // interestrate setzen
    double get_irate() const; // interestrate auslesen

    // Methoden zum Investments
    void set_inv(int, long int); // investment setzen
    long int get_inv(int) const; // investment auslesen
    int get_inv_years() const;

    // Berechnungs-Methoden
    double get_kapitalwert() const;
    double get_abzinsung(int) const;

private:

    vector<long int> inv;
    double irate;
};

#endif    /* NPV_H */
#include "npv.h"
#include <vector>
using namespace std;


// Standardkonstruktor
npv::npv() :
inv(0), irate(0) {
}

// Konstruktor für vorgebene Werte mit fester Rate
npv::npv(vector<long int> inv_value, double irate_value) :
inv(inv_value), irate(interestrate(irate_value)) {
}

// Konstruktor für Zufallsgenerierte Einträge
npv::npv(int iyears) :
inv(0), irate(0) {
    srand(time(NULL));
    vector<long int> inv_value(iyears);

    irate = interestrate(rand() % 100 + 1);

    inv_value.at(0) = (-1) * rand() % 100000 + 1;

    for (int i = 1; i < iyears; i++) {
	inv_value.at(i) = rand() % 10000 - rand() % 10000;
    }

    inv = inv_value;

}

// Anzahl der Einträge einer Zahlungsreihe auslesen
int npv::get_inv_years()const {
    return inv.size();
}

// Investment im Jahr t auslesen
long int npv::get_inv(int t) const {
    return inv.at(t);
}

// Investmentrate auslesen
double npv::get_irate() const {
    return irate * 100;
}

// Veränderung der Zahlungsreihe
void npv::set_inv(int t, long int ivalue) {
    inv.at(t) = ivalue;
}

// Kapitalwert berechnen
double npv::get_kapitalwert() const {
    long int kapitalwert = inv.at(0);

    for (int i = 1; i < inv.size(); i++) {
	kapitalwert = kapitalwert + get_abzinsung(i);
    }

    return nachkommastelle(kapitalwert, 2) / 100;
}

// Abzinsung für das Jahr t
double npv::get_abzinsung(int iyear) const {
    double dresult = 0;
    double ddivision = 1;
    long int ivalue = inv.at(iyear);

    for (int i = 0; i < iyear; i++) {
	ddivision = ddivision * (1 + irate);
    }
    if (ddivision != 0) {
	dresult = ivalue / ddivision;
    } else {
	error("Interest Rate bei diesem Objekt erzeugt Division durch 0");
    }

    return dresult;
}


// Nachkommastelle mit Genauigkeit t berechnen
double nachkommastelle(double dwert, int istellen) {
    if (istellen > 0) {
	int imult = 1;

	for (int i = 0; i < istellen; i++) {
	    imult = imult * 10;
	}

	dwert = dwert*imult;
	dwert = dwert + 0, 5;
	dwert = floor(dwert);
	dwert = dwert / imult;

	return dwert;
    } else {
	error("Ungültige Eingabe für die Anzahl der Nachkommastellen");
    }
}

// irate umrechnen ( Aufruf aus Konstruktor )
double interestrate(double irate_new) {
    irate_new = irate_new / 100;
    irate_new = nachkommastelle(irate_new, 4);
    return irate_new;
}

// Ausgabe einer Zahlungsreihe
void ausgabe(const vector<npv>& vnpv, int iposition) {
    iposition = iposition - 1;
    if (iposition >= 0 && iposition < vnpv.size()) {
	cout << "\t" << "Kapitalanlage =\t " << vnpv[iposition].get_inv(0) << endl;
	for (int i = 1; i < vnpv[iposition].get_inv_years(); i++) {
	    cout << "\t" << i << ". Jahr =\t " << vnpv[iposition].get_inv(i) << endl;
	}
	cout << "\tInterestrate = " << vnpv[iposition].get_irate() << "%" << endl;
	cout << "\tKapitalwert = " << vnpv[iposition].get_kapitalwert() << endl;
    } else {
	error("Ungültige Eingabe bei der Auswahl des NPV.");
    }
}

// Anlage einer Zahlungsreihe
void anlegen(vector<npv>& vnpv, int ianlegen) {
    int iyears = 0;
    int ianschaffung = 0;
    int isaldo = 0;
    double drate = 0;

    // Interaktive Eingabe ausgewählt
    if (ianlegen == 1) {
	cout << "Anzahl der Jahre für die Zahlungsreihe:\t";

	if (cin >> iyears && iyears > 0) {
	    vector<long int> vinv(iyears + 1);

	    cout << "Bitte Anschaffungswert definieren:\t";
	    if (cin >> ianschaffung) {
		vinv.at(0) = ianschaffung;
	    } else {
		error("Ungültige Eingabe für den Anschaffungswert.");
	    }

	    for (int i = 1; i < iyears + 1; i++) {
		cout << i << ". Jahr = \t";

		if (cin >> isaldo) {
		    vinv.at(i) = isaldo;
		} else {
		    error("Ungültige Eingabe für saldierte Werte. Müssen positive oder negative ganze Zahlen sein.");
		}
	    }

	    cout << "Bitte Interest Rate angeben:\t";
	    if (cin >> drate) {
		vnpv.push_back(npv(vinv, drate));
	    } else {
		error("Ungültiger Wert für die Interest Rate");
	    }

	} else {
	    error("Ungültige Eingabe für die Anzahl der Jahre. Muss eine positive ganze Zahl sein.");
	}
    }

    // Zufall-Eingabe ausgewählt
    if (ianlegen == 2) {
	cout << "Anzahl der Jahre für die Zahlungsreihe:\t" << endl;
	if (cin >> iyears && iyears > 0) {
	    vnpv.push_back(npv(iyears + 1));
	} else {
	    error("Ungültige Eingabe für die Anzahl der Jahre. Muss eine positive ganze Zahl sein.");
	}
    }

    // Falsche Auswahl
    if (ianlegen > 2 || ianlegen < 1) {
	error("Werte für die Anlage eines NPV dürfen nur 1 oder 2 sein.");
    }
}
#include "npv.h"
using namespace std;

int main() {
   
    try {
	
	// Initialisierung von Variablen
	vector<npv> vnpv;
	vector <long int> vinv;
	bool bend = false;
	int imenu = 3;
	int ianlegen = 1;
	int iausgabe = 0;

	// Beispieleintrag Anfang 
	cout << "Beispiel von Wikipedia:" << endl;
	vinv.push_back(-100000);
	vinv.push_back(45000);
	vinv.push_back(45000);
	vinv.push_back(45000);
	vnpv.push_back(npv(vinv, 10));
	ausgabe(vnpv, iausgabe + 1);
	// Beispieleintrag Ende 

	// Menü Anfang
	while (bend == false) {
	    cout << endl;
	    cout << "Bitte wählen Sie eine der folgenden Funktionen aus:" << endl;
	    cout << "\t1. Neue Zahlungsreihe anlegen und berechnen" << endl;
	    cout << "\t2. Vorherige Zahlungsreihe anzeigen" << endl;
	    cout << "\t3. Programm beenden" << endl;
	    cout << endl;

	    cout << "Funktion:\t";
	    cin >> imenu;
	    if (!cin) {
		error("Ungültige Eingabe für das Menü. Nur ganze pos. Zahlen zwischen 1 und 3 erlaubt.");
	    }

	    // Funktion 3 Programm beenden 
	    if (imenu == 3) {
		bend = true;
	    }

	    // Funktion 2 Bestehendes Objekt anzeigen
	    if (imenu == 2) {
		cout << "Für welches Objekt? (Aktuell:" << vnpv.size() << ")" << endl;
		cout << "Bitte Ziffer angeben:\t";

		if (cin >> iausgabe) {
		    cout << endl;
		    ausgabe(vnpv, iausgabe);
		} else {
		    error("Ungültige Eingabe für die Ausgabe.");
		}
	    }

	    // Funktion 1 Neues Objekt anlegen
	    if (imenu == 1) {
		cout << "Interaktiv anlegen (1) oder Zufallsgeneriert (2)" << endl;
		cout << "Bitte Auswahl angeben:\t";

		if (cin >> ianlegen) {
		    cout << endl;
		    anlegen(vnpv, ianlegen);
		} else {
		    error("Ungültige Eingabe für Anlage eines NPV");
		}

	    }

	    // Fall:    Ungültige Menüauswahl
	    if (imenu > 3 || imenu < 1) {
		error("Ungültige Eingabe für das Menü");
	    }

	}
	// Menü Ende 

	return 0;
    }    // Try Ende 

    // Fangen von bekannten Fehlern 
    catch (exception&e) {
	cerr << e.what();
	cout << endl;
	cout << endl;
    }
    // Fangen von unbekannten Fehlern 
    catch (...) {
	cerr << "Unbekannter Fehler";
	cout << endl;
	cout << endl;
    }

}

b) Testen Sie aus einem main() Treiber, indem sie mindestens 10 Testfälle für kritische Stellen der Klasse dokumentieren, diese ausführen (Ergebnisse ebenfalls dokumentiert) und ggf. Ihren Quellcode verbessern und erneut testen. Zahlungsreihe und Zinssatz sollen wahlweise interaktiv eingegeben oder zufällig sinnvoll erzeigt werden können.

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahren Sie, wie Ihre Kommentardaten verarbeitet werden.

Table of Contents

Index