|
I-PROGRAMMIEREN1 WS 0203 - Vorlesung mit Übung
|
Aus der letzten Vorlesungen liegt nun ein Lastenheft und eine vereinfachte Systemanalyse zum EARTHSIMULATOR1 vor. Daraus kann man entnehmen, dass das Programm folgenden grundätzlichen Aufbau hat:
/************************************ * * esim1.c * * author: gdh * first: dec-02,02 * last: - * idea: Demoprogramm zur Umsetzung der Anforderungen an * EARTHSIMULATOR1 * * compilation: gcc -o esim1 esim1.c * usage: esim1 * **************************************************/ int main(void){ input_data(); /* Eingabe von Daten für Simulation */ while( BEDINGUNG ){ compute_quantities(); /* Berechne die Veränderungen der Quantitäten der einzelnen Groessen */ compute_money(); /* Berechne die Geldzu- und -abfluesse der verschiedenen Kassen */ show_states(); /* Anzeige der Werte nach neuer Berechnung */ BEDINGUNG = ask_for_interruption(); /* Unterbrechung aufgrund Voreinstellung oder aktueller Benutzeraktion */ } return (1); }
Nach der Eingabe notwendiger Daten für einen Simulationslauf tritt das Programm in eine Schleife ein, deren Inhalt darin besteht, die Zustandsveränderung der Erde vom Jahr t zum Nachfolgejahr t+1 zu berechnen, anzuzeigen und gegebenfalls 'Werte zu modifizieren. Die Berechnung kann man aufteilen in zwei Teilrechnungen: (a) Berechnung der Veränderungen in der Population (Zunahmen, Abnahmen); (b) Berechnungen der Geldflüsse zwischen den Grössen auf der Basis der neuen Mengenverhältnisse. Nachdem alle Berechnungen vorgenommen wurden, sollen (c) die neuen Werte auf dem Bildschirm angezeigt werden. Der Benutzer soll dann die Möglichkeit erhalten, (d) einzugreifen: die Simulation ganz stoppen oder nur einzelne Parameter justieren.
Im weiteren Verlauf soll dieses Grundschema nun Schritt für Schritt weiter ausgefüllt werden.
Das Programm beginnt mit der Abfrage von Daten vom Benutzer. Es stellt sich die Frage, welche Daten werden benötigt und in welchem Format sollen die Daten abgelegt werden?
Für die Beantwortung dieser Frage gibt es keine leichte Antwort, da die Antwort stark von Annahmen abhängig ist, welche Eigenschaften man dem Gegenstandsbereich zusprechen will. Die folgende Rekonstruktion ist von daher wieder nur eine Möglichkeit unter mehreren. Es wird angenommen, dass sich der Gegenstandsbereich anhand von Eigenschaften strukturieren lässt, die die sich als begrifflicher Baum ('conceptual graph') auffassen lassen (siehe Bild).
Strukturierung der Welt (earth) anhand von
Eigenschaften
In dieser Rekonstruktion wird also angenommen, dass die Erde ('earth') aus Ländern ('country') besteht, ein Land wiederum setzt sich zusammen aus einer Population ('population') sowie aus diversen Kassen bzw. Konten ('accounts'). Für eine Population wird ferner angenommen, dass sie in Phasen ('phase') zerfällt. Diese Annahmen implizieren eine bestimmte Struktur in der Welt; man nennt dies auch häufig eine Ontologie ('ontology').
Wie man leicht feststellen kann, ist diese Grundstruktur für unsere Simulation noch zu abstrakt. Sie enthält viele Eigenschaften noch nicht, die für die Simulation benötigt werden. Also muss man versuchen, weitere Strukturen zu finden, solange, bis alle Eigenschaften, die für die Simulation benötigt werden, in der Ontologie repräsentiert sind.
Als erstes soll überlegt werden, wie man die Eigenschaft Kassen bzw. Konten ('accounts') weiter analysieren kann. Ein Vorschlag für eine analyse wäre der folgender:
Strukturierung der Kassen anhand von
Eigenschaften
Es wird also angenommen, dass ein spezielles Konto (Kasse) folgende Elemente enthält:
in: Einnahmen
out: Ausgaben
sum: Summe von Einnahmen und Ausgaben
unit: Masseinheit (z.B. in Tausend, in Millionen)
currency Währungsbezeichnung
Übernimmt man diese Analyse, dann muss man sich fragen, wie man diese Eigenschaften mit den Mitteln der Sprache C kodieren kann. Eine naheliegende Möglichkeit ist die Übersetzung dieser Eigenschaften in eine Struktur, etwa:
#define CURRENCY_STRING_LENGTH 10 struct ACCOUNTS { float in; float out; float sum; float unit; char currency[CURRENCY_STRING_LENGTH]; };
Beispielhaft sei gezeigt, wie man die neue Datenstruktur ACCOUNT im Rahmen eines C-Programms nutzen kann. In eine Headerdatei esim1.h hinterlegt man die Definition der Struktur und im Hauptprogramm esim1.c definiert dann mittels des neuen Typs ACCOUNT die Variablen RK, AK, KK und AG. Bei der Definition kann man diese Variablen auf einen bestimmten Startwert hin initialisieren, wie im Beispiel demonstriert:
/************************************ * * esim1.h * * author: gdh * first: dec-02,02 * last: - * idea: Headerdatei zum Hauptprogramm esim1.c * **************************************************/ #define CURRENCY_STRING_LENGTH 10 struct ACCOUNT { float in; float out; float sum; float unit; char currency[CURRENCY_STRING_LENGTH]; };
/************************************ * * esim1.c * * author: gdh * first: dec-02,02 * last: - * idea: Demoprogramm zur Umsetzung der Anforderungen an * EARTHSIMULATOR1 * * compilation: gcc -o esim1 esim1.c * usage: esim1 * **************************************************/ #include <stdio.h> #include "esim1.h" int main(void){ /* EINRICHTEN VON KONTEN MIT DEFINIERTEM ANFANGSWERT (INITIALISIERUNG) */ struct ACCOUNT RK ={0.0, 0.0, 0.0, 1000.0, "Euro"}; struct ACCOUNT AK ={0.0, 0.0, 0.0, 1000.0, "Euro"}; struct ACCOUNT KK ={0.0, 0.0, 0.0, 1000.0, "Euro"}; struct ACCOUNT AG ={0.0, 0.0, 0.0, 1000.0, "Euro"}; /* KONTROLLAUSDRUCK (Beispiel RK und AK) */ printf("INHALT VON RK: \n"); printf("IN: %.2f \n",RK.in); printf("OUT: %.2f \n",RK.out); printf("SUM: %.2f \n",RK.sum); printf("UNIT: %.0f \n",RK.unit); printf("CURRENCY: %s \n",RK.currency); printf("INHALT VON AK: \n"); printf("IN: %.2f \n",AK.in); printf("OUT: %.2f \n",AK.out); printf("SUM: %.2f \n",AK.sum); printf("UNIT: %.0f \n",AK.unit); printf("CURRENCY: %s \n",AK.currency); return (1); }
Als nächstes soll überlegt werden, wie man die Eigenschaft Phase ('phase') weiter analysieren kann. Aufgrund der vorausgehenden Anforderungen legt sich folgendes Konzept nahe:
Strukturierung der Phase anhand von
Eigenschaften
Erläuterungen:
interval: Für eine Phase muss klar sein, welchem Zeitintervall (t,t') sie zugeordnet ist
number: die Anzahl der Miglieder der Population in dieser Phase
percentage_men: prozentualer Anteil der Männer
percentage_women: prozentualer Anteil der Frauen
birthrate: Geburtenrate, d.i. Anzahl der Kinder, die von einer Frau durchschnittlich in dieser Phase geboren werden
self_employed: die Selbständigen
employed: die Beschäftigten
unemployed: die registrierten Arbeitslosen
education: Personen, die sich überwiegend in der Ausbildung befinden (einschliesslich 'Kindheit')
retired_persons1 Personen, die aus einem unselbständigen Beschäftigtenverhältnis in ein Rentenverhältnis übergegangen sind
retired_persons2 Personen, die aus der Selbständigkeit in ein rentenähnliches Verhältnis übergegangen sind
sick_persons: prozentualer Anteil der kranken Menschen, die Geld aus der Krankenkasse beziehen
Mit dieser Analyse kann man die Menge der Personen, die eine Phase bilden, nach unterschiedlichen Eigenschaften in Untergruppen aufteilen. Neben allgemeinen Eigenschaften (wie interval, number, percentage_men, percentage_women und birthrate), die die ganze Phase betreffen, kann man Untergruppen unterscheiden (wie z.B. self_employed, employed, unemployed, education, retired_persons1, retired_persons2 und sick_persons). Übernimmt man diese Analyse, dann kann man, analog wie im Fall der Eigenschaft Konto (ACCOUNT), wieder eine entsprechende Struktur definieren. Allerdings würden dann noch Angaben darüber fehlen, wieviel jedes Mitglied der Untergruppen in die unterschiedlichen Kassen zu zahlen bzw. zu bekommen hätte.
Eine Möglichkeit, dieses Problem zu lösen, bestände darin, dass man sich auf den Standpunkt stellt, dass alle die genannten Untergruppen letztlich eine gemeinsame Struktur besitzen, nämlich die Struktur Zahler-Zahlungsempfänger ('PAYER_PAYEE'). Damit wäre folgende Analyse möglich:
Zusätzliche Strukturierung der Phase durch
Zuordnung der Untergruppen an eine weitere Struktur PAYER_PAYEE
Wie liesse sich solch eine Datenstruktur in der Sprache C realisieren? Ein Beispiel zeigt die folgende Datei esim2.h:
/************************************ * * esim2.h * * author: gdh * first: dec-02,02 * last: - * idea: Headerdatei zum Hauptprogramm esim2.c * **************************************************/ #define CURRENCY_STRING_LENGTH 10 struct ACCOUNT { float in; float out; float sum; float unit; char currency[CURRENCY_STRING_LENGTH]; }; struct PAYER_PAYEE { float percentage_of_number; float actual_yearly_income; float last_yearly_income; float former_yearly_income; float RK_payment; float RK_income; float AK_payment; float AK_income; float KK_payment; float KK_income; float XRA_payment; float XRA_income; float AG_payment; float AG_income; }; struct PHASE { unsigned int interval[2]; unsigned long int number; float percentage_men; float percentage_women; float birthrate; struct PAYER_PAYEE self_employed; struct PAYER_PAYEE employed; struct PAYER_PAYEE unemployed; struct PAYER_PAYEE education; struct PAYER_PAYEE retired_persons1; struct PAYER_PAYEE retired_persons2; struct PAYER_PAYEE sick_persons; };
Man kann deutlich erkennen, wie die beiden Strukturen PAYER_PAYEE sowie PHASE miteinander verschränkt werden. Da die Struktur PHASE die Struktur PAYER_PAYEE voraussetzt, muss die Struktur PAYER_PAYEE zuerst definiert werden. Nachdem dies geschehen ist, kann man in der neuen Struktur PHASE Elemente vom Typ PAYER_PAYEE definieren. Dies sind genau die Untergruppen, von denen wir wissen, dass sie entweder in eine der Kassen/ Konten einzahlen oder wenigstens von einer der Kassen Geld bekommen. Man kann aber auch erkennen, dass in der Struktur PAYER_PAYEE noch vier Elemente hinzugenommen wurden, die nicht im Bild dargestellt sind:
float percentage_of_number; der prozentuale Anteil der Untergruppe an der Gesamtzahl der Phase
float actual_yearly_income; das aktuelle durchschnittliche jährliche Bruttoeinkommen der Untergruppe
float last_yearly_income; das letzte durchschnittliche jährliche Bruttoeinkommen der Untergruppe (bei registrierten Arbeitslosen)
float former_yearly_income; das frühere durchschnittliche jährliche Bruttoeinkommen der Untergruppe (bei Rentnern)
Das folgende kleine Programm zeigt beispielhaft, wie man diese neuen Strukturen PHASE und PAYER_PAYEE verwenden kann.
/************************************ * * esim2.c * * author: gdh * first: dec-02,02 * last: - * idea: Demoprogramm zur Umsetzung der Anforderungen an * EARTHSIMULATOR1 * * compilation: gcc -o esim2 esim2.c * usage: esim2 * **************************************************/ #include <stdio.h> #include "esim2.h" #define COUNTRY_PHASE_NUMBER 5 int main(void){ /* EINRICHTEN VON KONTEN MIT DEFINIERTEM ANFANGSWERT (INITIALISIERUNG) */ struct ACCOUNT RK ={0.0, 0.0, 0.0, 1000.0, "Euro"}; struct ACCOUNT AK ={0.0, 0.0, 0.0, 1000.0, "Euro"}; struct ACCOUNT KK ={0.0, 0.0, 0.0, 1000.0, "Euro"}; struct ACCOUNT AG ={0.0, 0.0, 0.0, 1000.0, "Euro"}; /* EINRICHTEN VON PHASEN */ struct PHASE germany[COUNTRY_PHASE_NUMBER]; /* KONTROLLAUSDRUCK KONTEN (Beispiel RK und AK) */ printf("INHALT VON RK: \n"); printf("IN: %.2f \n",RK.in); printf("OUT: %.2f \n",RK.out); printf("SUM: %.2f \n",RK.sum); printf("UNIT: %.0f \n",RK.unit); printf("CURRENCY: %s \n",RK.currency); printf("INHALT VON AK: \n"); printf("IN: %.2f \n",AK.in); printf("OUT: %.2f \n",AK.out); printf("SUM: %.2f \n",AK.sum); printf("UNIT: %.0f \n",AK.unit); printf("CURRENCY: %s \n",AK.currency); /* BEISPIEL FUER DIE EINGABE UND DAS AUSLESEN VON DATEN BEI DER STRUKTUR PHASE */ printf("EINGABE DES INTERVALLS ('a b') in Jahren : "); scanf("%d %d",&(germany[0].interval[0]), &(germany[0].interval[1])); printf("\nKONTROLLE DES INTERVALLS ('a b') in Jahren\n"); printf("germany 0: Anfang = %d Ende = %d\n",germany[0].interval[0], germany[0].interval[1]); printf("\nEINGABE DER ANZAHL DER PHASE (in Mio.) : "); scanf("%d",&(germany[0].number)); printf("\nKONTROLLE DER ANZAHL DER PHASE (in Mio.) : "); printf("germany 0: Anzahl = %d\n",germany[0].number); printf("\nEINGABE DES PROZENTSAZES VON SELBSTAENDIGEN AN DER PHASE ('x.x') : "); scanf("%f",&(germany[0].self_employed.percentage_of_number)); printf("\nKONTROLLE DES PROZENTSAZES VON SELBSTAENDIGEN AN DER PHASE\n"); printf("germany 0: Prozentsatz Selbstendige = %.2f\n",germany[0].self_employed.percentage_of_number); return (1); }
Bilden sie ein Team von max.3 Mitgliedern
Erstellung Sie gemeinsam einen Text mit Namen und Matr.Nr. der AutorenInnen. Abgabe einer Kopie des Textes an den Dozenten vor Beginn der Vorlesung am Di (1 Woche nach Aufgabenstellung). Falls die Aufgabe ausführbaren Programmcode enthält wäre die zusätzliche Übergabe des Quelltextes auf Diskette oder per email wünschenswert. Im Falle von Programmcode muss im Programmtext auch nochmals Name und Matr.Nr. erscheinen.
Präsentation der Lösung als Team vor der gesamten Gruppe. Präsentationszeit (abhängig von der Gesamtzahl der Teams) 3-5 Min. Mögliche Punkte: 1-3 im Normalfall. (Im Falle von mehr als 1 Autor ist die ausführliche Besprechung in der Übung Voraussetzung für die Vergabe der Punkte!)
Versuchen Sie in dem Text Antworten auf folgende Aufgaben zu formulieren:
Auf der Basis der Spezifikationen des EARTHSIMULATOR1 aus der Vorlesung VL9 sowie aufgrund der Analyse möglicher Datenstrukturen aus VL 10 erarbeiten Sie einen Vorschlag für die Eingabe der Daten für ein Land.