kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Informatik -- Fortsetzung Wissenschaftliches Rechnen -- Lehrveranstaltung vom 15.04.2024

(EN google-translate)

(PL google-translate)

Themen

  1. Wiederholung und Vertiefung zu Datentypen
  2. Wiederholung und Vertiefung zu Kontrollstrukturen
  3. Wiederholung und Vertiefung zu Funktionen
  4. Rückblick auf den Feder-Masse-Schwinger
  5. Allgemeine Ergänzungen zu Simulationstechnik
  6. Preview Virtual Reality Modeling Language (VRML)
  7. Ein weiteres Beispiel zu Simulationstechnik: Das Räuber-Beute-Modell

1. Wiederholung und Vertiefung zu Datentypen

QUIZ: Mit einer Vairable welchen Datentyps würden Sie jeweils die folgenden Datenelemente speichern?:

1) 42
2) 'A'
3) 0.5
4) true

Code 0-1: Datenelemente

  • Arrays lassen sich u.a. durch Verwendung eckiger Klammern bilden.
  • Sollen quasi in einem Vektor zwei double-Werte gespeichert werden, so kann das so geschehen:
double vektor[2];
vektor[0] = 1.2;
vektor[1] = -0.9;

Code 0-2: double-Array

  • Schauen Sie einmal auf die Array- und Funktions-basierte Variante des Simulators von letzter Woche:
  • Siehe "Code 0-7: federmasse4.cpp ":
10_Informatik1/06_Anwendungsgebiete/01_Simulationstechnik
  • Wir analysieren das Programm und sehen, wo überall Arrays verwendet werden.
  • Interessant: Arrays können auf besondere Weise an Funktionen übergeben werden, siehe: void berechneSteigung(double *st,double *y)...
  • double *y übernimmt die Speicheradresse, ab der das Array gespeichert ist.
  • Eine solche Art der Übergabe einer Variablen nennt man "Call by Reference", da keine Kopie der Daten übergeben werden, sondern ein Verweis dorthin, wo sie sich befinden.

2. Wiederholung und Vertiefung zu Kontrollstrukturen

  • Kontrollstrukturen regeln den Programmfluss.
  • Abhängig von bestimmten Bedingungen, können bestimmte Code-Teile verarbeitet, oder übersprungen werden.
  • Nachfolgend sind einige Kontrollstrukturen in C/C++ aufgeführt:

//if-Anweisung
if(x>7)
{
    cout<<"x ist groesser als 7."<<endl;
}

//while-Schleife
while(x<5)
{
   x++; //Postinkrement-Operator, erhöht x um +1. 
   cout<<"x="<<x<<endl;
}

//for-Schleife
for(int i=0;i<5;i++)
{
   cout<<"i="<<endl;
}

//do-while-Schleife
do
{
   x++;
   cout<<"x="<<x<<endl;
}while(x<5);


Code 0-3: Kontrollstrukturen

  • Kontrollstrukturen besitzen als Argument einen Ausdruck, dessen Ergebnis ein boolscher Wert ist (true oder false).
  • Je nachdem, welches Ergebnis das Argument liefert, werden die Befehle im Rumpf (geschweifte Klammern) der Kontrollstruktur ausgeführt, oder nicht, bzw. übersprungen.
  • Operationen, die boolsche Werte zum Ergebnis haben, sind Vergleichsoperatoren (<,>,==, also ist kleiner als, ist größer als, hat den gleichen Wert wie).
ÜBUNG
  • Betten Sie alle oben stehenden Kontrollsttrukturen jeweils in funktionierende Programm ein und testen diese.
  • Fertigen Sie ein Flussdiagramm von jedem dieser Programme an.

3. Wiederholung und Vertiefung zu Funktionen

  • Es macht Sinn, mehrfach mit jeweils verschiedenen Werten ausgeführte Berechnungsvorschriften in Funktionen auszulagern.
  • Dies führt zu übersichtlicherem Quelltext und wiederverwendbaren Strukturen.
  • Insbesondere können nützliche Funktionen in Header-Dateien ausgelagert werden.
  • Eigene Haeder-Dateien können in das Hauptprogramm mit #include "meinefunktion.h" eingebettet werden, wobei meinefunktion.h dann eine Funktion ist, die im gleichen Verzeichnis liegt, wie das Hauptprogramm.
  • Beispiel:
double findeMaximum(double *array, int anzahl)
{
    double ergebnis = array[0];
    for(int i=1;i<anzahl;i++)
    {
        if(array[i]>ergebnis)
        {
            ergebnis = array[i];
        }
    }
    return ergebnis;
}

Code 0-4: maximum.h

#include <iostream>
#include "maximum.h"
using namespace std;
int main(void)
{
    double array[] = {-0.5,3.7,-1.5,2.5,7.3,2.1,3.0};
    int anzahl = sizeof(array)/sizeof(double); //Bestimmung der Anzahl der Array-Elemente

    cout<<"Array: ";
    for(int i=0;i<anzahl;i++)
    {
        cout<<" "<<array[i];
    }
    cout<<endl;

    cout<<"Groesstes Element:"<<findeMaximum(array,anzahl)<<endl;

    return 0;
}

Code 0-5: hauptprogramm.cpp

linux@Xubuntu2004:~/Programm5_LV4_15_April$ g++ -o hauptprogramm hauptprogramm.cpp 
linux@Xubuntu2004:~/Programm5_LV4_15_April$ ./hauptprogramm 
Array:  -0.5 3.7 -1.5 2.5 7.3 2.1 3
Groesstes Element:7.3

Code 0-6: Konsolen Ein- und Ausgaben

ÜBUNGEN
  • Ergänzen Sie mit minimum.h eine Funktion, die das Minimum bestimmt und testen sie in dem Hauptprogramm.

4. Rückblick auf den Feder-Masse-Schwinger

10_Informatik1/06_Anwendungsgebiete/01_Simulationstechnik

5. Allgemeine Ergänzungen zu Simulationstechnik

50_Simulationstechnik/01_Systemtheorie/02_Modell

Preview Virtual Reality Modeling Language (VRML)

50_Simulationstechnik/03_VRML

6. Ein weiteres Beispiel zu Simulationstechnik: Das Räuber-Beute-Modell

siehe zur Vertiefung:

https://de.wikipedia.org/wiki/R%C3%A4uber-Beute-Beziehung
ÜBUNG
12_Technologie/03_Lottka_Volterra
  • Übertragen Sie das Programm "Code 0-2: Gesamter Quelltext zu nachfolgend sichtbarem Beispiel." unten nach C++.
  • Erweitern Sie das Programm so, dass die "Wellenbewegung" der Populationen in der Konsole animiert werden.
  • Nutzen Sie dazu folgendes Programm zur Zeitverzögerung der einzelnen Darstellungsschritte:
#include <iostream>
using namespace std;
int main(void)
{
    double Raeuber_alt = 10.0;
    double Raeuber_neu = 0.0;
    double Beute_alt = 100.0;
    double Beute_neu = 0.0;

    double dt = 0.01;
    double  t = 0.0;

    while(t<1.0)
    {
        cout<<Raeuber_alt<<" "<<Beute_alt<<endl;
        Beute_neu   = Beute_alt + (Beute_alt*1.0  - Beute_alt*Raeuber_alt*0.01)*dt;
        Raeuber_neu = Raeuber_alt + (-Raeuber_alt*1.0  + Beute_alt*Raeuber_alt*0.01)*dt;
        Raeuber_alt = Raeuber_neu;
        Beute_alt = Beute_neu;
        t+=dt;
    }    
    return 0;
}

Code 0-7: NEUE VORLAGE ("Balken" und Verlangsamung sind zu ergänzen.)

#include <iostream>
#include <time.h>
using namespace std;
int main(void)
{
    int x=0;
    clock_t t_start , t_end; 

    t_start = clock(); 

    for(int i=0;i<500000000;i++)
        x++;

    t_end = clock(); 

    cout<<"Dauer des Prozesses in Nanosekunden: "<<(t_end-t_start)<<endl;
}

Code 0-8: Zeitmessung mit C++.


Wie kann man auf dieser Grundlage ein Programm schreiben, dass eine Schleife in einem definierten Tempo ausführt?


  • Testen und analysieren Sie das nachfolgende Programm und machen es sich zunutze für die Visualisierung des Verhältnisses zwischen Räubern und Beute:
#include <iostream>
#include <time.h>
#include <math.h>
using namespace std;
int main(void)
{
    double t=0.0;
    double frequenz=0.1;
    double y=0.0;
    int amplitude=0;
    clock_t tt; 
    tt=clock();
    while(true)
    {
        y = sin(2.0*M_PI*frequenz*t);
        amplitude = (int)round((y+1.0)*40.0);
        for(int i=0;i<amplitude;i++)
            cout<<"#";
        cout<<endl;
        t+=0.1;
        while(clock()<tt+100000);
        tt=clock();
    }
}

Code 0-9: sinus.cpp

ÜBUNGEN
  • Machen Sie die Aufteilung in Funktion und Hauptprogramm bei "Code 1.4-6: Konsolen Ein- und Ausgaben " rückgängig: Alles soll in der main-Methode passieren.

Themen für die Übung am 17.04.

  1. Varianten der if-Anweisung: if / else / else if.
  2. Besprechung der bisheringen Übungsaufgaben und gemeinsame Entwicklung einer Auswahl an Musterlösungen.
  3. Entwicklung eines Programms, um Widerstandswerte oder -farbkodierungen zu bestimmen code2wert bzw. wert2code.

if(i>5)
{
   cout<<"i ist groesser als 5"<<endl;
}

if(i>5)
{
   cout<<"i ist groesser als 5"<<endl;
}
else
{
   cout<<"i ist kleiner oder gleich 5"<<endl;
}

if(i>5)
{
   cout<<"i ist groesser als 5"<<endl;
}
else if(i==0)
{
   cout<<"i ist Null"<<endl;
}
else
{
   cout<<"i ist kleiner oder gleich 5, aber ungleich Null"<<endl;
}

Code 0-10: Varianten der if-Anweisung: if / else / else if.

siehe beispielsweise: https://www.conrad.de/de/ratgeber/handwerk/widerstands-farbcode.html
MUSTERLÖSUNGEN

Gegebene Kontrollstrukturen einbetten:

#include <iostream>
using namespace std;
int main(void)
{
    //for-Schleife
    for(int i=0;i<5;i++)
    {
        cout<<"i="<<i<<endl;
    }//for(int i=0;i<5;i++)

    return 0;
}

Code 0-11: Beispiel mit for.

#include <iostream>
using namespace std;
int main(void)
{
    int x = 0;
    //while-Schleife
    while(x<5)
    {
        x++; //Postinkrement-Operator, erhöht x um +1. 
        cout<<"x="<<x<<endl;
    }
    return 0;
}

Code 0-12: Beispiel mit while.

Räuber Beute Übung
#include <iostream>
#include <math.h>
#include <time.h>
using namespace std;
int main(void)
{
    double Raeuber_alt = 10.0;
    double Raeuber_neu = 0.0;
    double Beute_alt = 100.0;
    double Beute_neu = 0.0;

    double dt = 0.01;
    double  t = 0.0;
    clock_t tt = clock();
    while(true)
    {
        int beuterauten = (int)round(Beute_alt/4.0);
        int raeuberplusse = (int)round(Raeuber_alt/4.0);
        if(beuterauten<raeuberplusse)
        {
            for(int i=0;i<beuterauten;i++)
            {
                cout<<'#';
            }
            for(int i=beuterauten;i<=raeuberplusse;i++)
            {
                cout<<'+';
            }
            cout<<endl;
        }
        else
        {
            for(int i=0;i<raeuberplusse;i++)
            {
                cout<<'+';
            }
            for(int i=raeuberplusse;i<=beuterauten;i++)
            {
                cout<<'#';
            }
            cout<<endl;
        }

        Beute_neu   = Beute_alt + (Beute_alt*1.0  - Beute_alt*Raeuber_alt*0.01)*dt;
        Raeuber_neu = Raeuber_alt + (-Raeuber_alt*1.0  + Beute_alt*Raeuber_alt*0.01)*dt;
        Raeuber_alt = Raeuber_neu;
        Beute_alt = Beute_neu;
        t+=dt;

        while(clock()<tt+10000); //Warteschleife ohne Rumpf, wartet 0,1 Sekunde.
        tt = clock(); //Aktualisieren der Systemzeit in tt.
    }    
    return 0;
}

Code 0-13: Aktueller Stand.

Lehrveranstaltung am 22.04.2024


Veränderung der Oranisation: eine Vorlesung soll es ab jetzt immer Mittwochs geben, wohingegen der Montag Übungen vorbehalten sein soll.


  • Die Übungen sollen aber stets mit einer Einleitung beginnen, die beispielsweise auch auf historische Zusammenhänge verweist.
  • In den Beispielen zur Simulationstechnik zeigen sich Computerprogramme als (dynamische, abstrahierende) Modelle lokal begrenzter Gegenstände aus Natur und Technik.
  • Geläufiger sind Beispiele, wo Computerprogramme gespeichertes Wissen einer Anfrage gemäß aufbereiten, wie bei Benutzerschnittstellen von Datenbanken, KI-Anwendungen wie chatGPT, oder eben in Form kleiner Hilfsprogramme, wie das in der aktuellen Übung zur Bestimmung der Farbcodes zu einem Widerstandswert.
  • Dies hat eine lange Tradition: So kam in den Anfängen der Computertechnik die Idee des GPS, des "General Problem Solver" auf.
  • In dieser ersten Entwicklungsphase in den 1970ern setzten sich die Vertreter der symbolischen Künstlichen Intelligenz mit Expertensystemen auf der Basis deklarativer Programmiersprachen wie Prolog oder Lisp gegenüber Konnektionistischen Ansätzen durch.
  • Wissen sollte durch Experten in eine elektronische, automatisiert logisch verarbeitbare Form übertragen werden.

Beim heutigen Stand der Leistungsfähigkeit der Computer und mit Erfindung von Deep Learning verbuchen konnektionistische Ansätze große Erfolge:

Koreaner Lee Sedol wird 2016 von Alpha Go besiegt. https://youtu.be/sUALRX3KhyQ

Die sich immer weiter steigernde Fähigkeit von Computersystemen, Probleme im menschlichen Umfeld zu lösen, wirft mittlerweile auch ethische Fragen auf, wie sie in der Moral Machine des MIT thematisiert werden:

Moral machine -- https://www.moralmachine.net/
VORÜBUNGEN (gemeinsame Saalübung)

Schreiben Sie jeweils ein zu dem Flussdiagrammen passendes Programm:

Countdown.

Bild 0-1: Countdown.

#include <iostream>
using namespace std;
int main(void)
{
    int i=10;
    cout<<"Countdown:"<<endl;
    while(i>=0)
    {
        cout<<i<<endl;
        i=i-1;
    } 
    cout<<"i am Ende: "<<i<<endl;
    return 0;
}

Code 0-14: Musterlösung.

#include <iostream>
using namespace std;
int main(void)
{
    int i=10;
    cout<<"Countdown:"<<endl;
    do
    {
        cout<<i<<endl;
        i=i-1;
    } while(i>=0);
    cout<<"i am Ende: "<<i<<endl;
    return 0;
}

Code 0-15: Variante mit do-while.

Hier noch einmal die Übungsaufgabe ausformuliert:

ÜBUNG 1

Arbeitshinweise:


  1. Arbeiten Sie in Zweiergruppen
  2. Diskutieren Sie die Programmierschritte untereinander
  3. Teilen Sie die Gesamtaufgabe in aufeinander aufbauende für sich funktionierende Teilschritte auf
  • Schreiben Sie ein Programm, bei dem als Input ein Widerstandswert als Zahl eingegeben wird und das dann den zugehörigen Zahlencode bei Widerständen mit drei Ringen ausgibt.
  • Beispiele: 100 Ohm => braun schwarz braun, 47000 Ohm => gelb lila orange, 2200 Ohm => rot rot rot
  • Dabei gibt der erste Ring den Zehner, der zweite den Einer an und der dritte eine Zehnerpotenz, womit diese Zahl multipliziert wird.
  • Eine entsprechende Tabelle findet sich beispielsweise auf Wikipedia:
Farbkodierung von Widerständen mit 3 oder 4 Ringen, Quelle: Wikipedia, https://de.wikipedia.org/wiki/Widerstand_(Bauelement)#Farbkodierung_auf_Widerst%C3%A4nden

Bild 0-2: Farbkodierung von Widerständen mit 3 oder 4 Ringen, Quelle: Wikipedia, https://de.wikipedia.org/wiki/Widerstand_(Bauelement)#Farbkodierung_auf_Widerst%C3%A4nden

Bisher wurde eine Hilfestellung in Form eines Flussdiagramms gegeben, um den Code des dritten Rings aus dem Widerstandswert zu gewinnen. Dabei meint "Code" die Ausgabe der Zahl, die mit dem entsprechenden Farbwert verknüpft ist:

Code Farbe Bedeutung
0 schwarz 10^0
1 braun 10^1
2 rot 10^2
3 orange 10^3
4 gelb 10^4
5 grün 10^5
6 blau 10^6
7 lila 10^7
8 grau 10^8
9 weiss 10^9

Tabelle 0-1: Zuordnung Code, Farbe, Bedeutung beim dritten Ring.

Hilfestellung: Flussdiagramm, um den Code des dritten Rings zu bestimmen.

Bild 0-3: Hilfestellung: Flussdiagramm, um den Code des dritten Rings zu bestimmen.


Entwickeln Sie das Programm in aufeinander aufbauenden Stufen:


  1. Stufe: Bestimmung und Ausgabe des Codes des dritten Rings gemäß Hilfestellung
  2. Stufe: Ergänzende Ausgabe der dem dritten Ring zugehörigen Farbe als Wort, z.B. 2 (rot), oder 7 (lila).
  3. Stufe: Bestimmung und Ausgabe aller drei Ringe.
Musterlösung
#include <iostream>
using namespace std;

void gibFarbcodeAus(int code)
{
    if(code==0)
        cout<<"schwarz";
    else if(code==1)
        cout<<"braun";
    else if(code==2)
        cout<<"rot";
    else if(code==3)
        cout<<"orange";
    else if(code==4)
        cout<<"gelb";
    else if(code==5)
        cout<<"gruen";
    else if(code==6)
        cout<<"blau";
    else if(code==7)
        cout<<"violett";
    else if(code==8)
        cout<<"grau";
    else //if(code==9)
        cout<<"weiss";
}

int main(void)
{
    int wert = 0;
    int code = 0;
    cout<<"Geben Sie den Widerstandswert in Ohm an:";
    cin>>wert;
    cout<<endl;
    //Code des dritten Rings bestimmen:
    while(wert>100)
    {
        wert = wert/10;
        code = code + 1;
    }
  
    int zweiter_ring = wert - (wert/10)*10;

    cout<<"Code erster   Ring: "<<(wert/10)<<" (";
    gibFarbcodeAus((wert/10));
    cout<<")"<<endl;
    cout<<"Code zweiter  Ring: "<<zweiter_ring<<" (";
    gibFarbcodeAus(zweiter_ring);
    cout<<")"<<endl;
    cout<<"Code dritter  Ring: "<<code<<" (";
    gibFarbcodeAus(code);
    cout<<")"<<endl;

    return 0;
}


Code 0-16: Musterlösung

Musterlösung mit Schleife
#include <iostream>
using namespace std;
int main(void)
{
    int wert = 0;
    int code = 0;
    int erster_ring = 0;
    cout<<"Geben Sie den Widerstandswert in Ohm an:";
    cin>>wert;
    cout<<endl;
    //Code des dritten Rings bestimmen:
    while(wert>100)
    {
        wert = wert/10;
        code = code + 1;
    }
    //Code des ersten Rings bestimmen:
    while(wert>10)
    {
        wert = wert-10;
        erster_ring = erster_ring + 1;
    }
    cout<<erster_ring<<" "<<wert<<" "<<code<<endl;  

    return 0;
}

Code 0-17: Musterlösung mit Schleife

Musterlösung mit Modulo
#include <iostream>
using namespace std;
int main(void)
{
    int wert = 0;
    int code = 0;
    cout<<"Geben Sie den Widerstandswert in Ohm an:";
    cin>>wert;
    cout<<endl;
    //Code des dritten Rings bestimmen:
    while(wert>100)
    {
        wert = wert/10;
        code = code + 1;
    }
  
//    int zweiter_ring = wert - (wert/10)*10;
    int zweiter_ring = wert%10;

    cout<<"Code erster   Ring: "<<(wert/10)<<endl;
    cout<<"Code zweiter  Ring: "<<zweiter_ring<<endl;
    cout<<"Code dritter  Ring: "<<code<<endl;

    return 0;
}

Code 0-18: Musterlösung mit Modulo

ÜBUNG 2
  • Implementieren Sie auch den umgekehrten Fall, bei dem Farbcodes eingegeben werden und der zugehörige Widerstandswert in Ohm daraus bestimmt und ausgegeben wird.