Java/Modellrechner und Java/Rekursion: Unterschied zwischen den Seiten

Aus ZUM-Unterrichten
< Java(Unterschied zwischen Seiten)
main>ZUM-Wiki-Bot
(</source>)
 
main>ZUM-Wiki-Bot
(</source>)
 
Zeile 1: Zeile 1:
{{Kurzinfo-2|Java|Idee}}
{{Kurzinfo-3|Java|Idee|Links}}
Ein Modellrechner, der bereits ein lauffähiges Programm im Speicher hat, ist folgendermaßen aufgebaut:
{{Zitat wpde|
Als '''Rekursion''' (auch Rekurrenz oder Rekursivität), von lateinisch recurrere entspr. zurücklaufen, bezeichnet man den Aufruf oder die Definition einer Funktion durch sich selbst. Die gegenseitige Rekursion bildet sich durch den gegenseitigen Verweis zweier oder mehrerer Funktionen auf einander.


{| class="prettytable"
In vielen Fällen ist die Rekursion eine von mehreren möglichen Problemlösungsstrategien, sie führt oft zu eleganten mathematischen Lösungen. In der Regel sind rekursive Programme (als Darstellung eines rekursiven Problems) zwar wesentlich kompakter (also kürzer) als die iterativen Varianten, dafür sind sie etwas langsamer und der Speicheraufwand ist höher.
| <center>Nr.</center>
| <center>Programmspeicher</center>
| Datenspeicher


|-
Ohne geeignete Abbruchbedingung geraten solche rückbezüglichen Aufrufe in einen so genannten infiniten Regress (umgangssprachlich Endlosschleife). Zur Vermeidung von infinitem Regress insbesondere in Computerprogrammen bedient man sich der semantischen Verifikation von rekursiven Funktionen. Der Beweis, dass kein infiniter Regress vorliegt, wird dann zumeist mittels einer Schleifeninvariante geführt (siehe auch Invariante). Dieser Beweis ist allerdings nicht immer möglich (siehe Halteproblem).
| <center>0</center>
|Rekursion|21.11.2006}}
| <center>2 (add)</center>
| 0


|-
==Beispiel==
| <center>1</center>
| <center>5</center>
| 1


|-
Fakultät:
| <center>2</center>
5! = 1 * 2 * 3 * 4 * 5
| <center>3 (sub)</center>
| 2


|-
===rekursiv===
| <center>3</center>
1 fakultät_rekursiv(n)
| <center>6</center>
2 {
| 3
3   wenn n <= 1
4      dann return 1
5      sonst return ( n * fakultät_rekursiv(n-1) )
6 }


|-
===iterativ===
| <center>4</center>
1 fakultät_iterativ(n)
| <center>4 (cmp)</center>
2 {
| 4
3    fakultät = 1
4     faktor = 2
5    solange faktor <= n
6    {
7        fakultät = fakultät * faktor
8        faktor = faktor + 1
9    }
10    return fakultät
11}


|-
| <center>5</center>
| <center>6</center>
| 5 7


|-
==Listenausgabe==
| <center>6</center>
(Setzt [[Java/List]] o.ä. voraus)
| <center>5 (jmp)</center>
| 6 3


|-
| <center>7</center>
| <center>0</center>
| 7
|-
| <center>8</center>
| <center>1</center>
| 8
|-
| <center>...</center>
|
| 9
|}
{| class="prettytable"
| '''Befehle (Maschinensprache)'''
1 '''stp''' – Stoppt die Programmausführung
2 '''add X''' – addiert zu der mit X angegebenen Speicherstelle 1
3 '''sub X''' – subtrahiert von der mit X angegebenen Speicherstelle 1
4 '''cmp X''' – prueft, ob in der mit X angegebenen Speicherzelle der Wert 0 eingetragen. Wenn ja überspringt der Programmzähler 2 Schritte, wenn nein setzt er das Programm an der folgenden Stelle fort.
5 '''jmp X''' – Setzt den Programmzähler auf X
|}
{{Aufgabe|
Hinweis: JMP beinhaltet noch einen Bug!
Leseprobe zum Programm: Beim Programmaufruf wird folgendes ausgeführt:
'''add 5''', da in Programmspeicher 0 der Befehl 2, also add, steht und in Programmspeicher 1 eine 5 eingetragen ist. Also wird Programmspeicher 5 um ein erhöht (in diesem Fall auf 8).
Anschließend steht der Programmzähler (angedeutet als blauer Pfeil) auf Position 2.
Das oben bereits eingetragene Programm führt die Addition von Datenspeicher 5 und 6 durch.
Dazu wird Speicherzelle 5 solange um 1 erhöht und Speicherzelle 6 solange um 1 verkleinert, bis Speicherstelle 6 den Wert 0 hat.
a) Ändern Sie das Maschinensprachenprogramm so, dass von der 7 die 3 abgezogen wird, also als Ergebnis eine 4 in Speicherplatz 5 steht.
b) Ist bei dem angegebenen Rechner die Anforderung an die „Von-Neumann-Architektur“ eingehalten? Begründen Sie!
c) Bei der Simulation in Java lässt sich die Programmausführung wie folgt simulieren (Quelltext z.T. angegeben).
c1) Beschreiben Sie, wie die Methode '''run()''' funktioniert.
c2) Schreiben Sie – analog zur unten angegebenen Methode addiereEins() - die Methode '''subtrahiereEins()'''.
c3) Schreiben Sie die Methode '''springeAuf()''', die den jmp X Befehl simulieren soll. Der nächste Programmplatz wird ausgelesen und der Programmzähler auf die entsprechende Position gesetzt.
c4) Schreiben Sie die Methode '''list(), '''die auf der Konsole den gesamten Inhalt des Programmspeichers ausgibt (siehe Abbildung mit einer Beispielabbildung).
d) Nehmen Sie Stellung zu der Frage, ob die Auswahl der Datentypen, also [[Java/Array|Array]] für den Datenspeicher und [[Java/List|List]] für den Programmspeicher eine gute Wahl war. Wägen Sie Vor- und Nachteile ab und geben Sie Alternativen an.}}
'''Quelltext der Klasse Modellrechner'''
<source lang="java">
<source lang="java">
public class Modellrechner
     private void rekursiveAusgabe() {
{
         if (liste.isBehind()){
    private List programmspeicher;
             System.out.println("Fertig.");
     private int[] speicher;
   
    public Modellrechner()
    {
        programmspeicher=new List();
        speicher = new int[10];
        for (int i=0;i<10;i++) speicher[i]=0;
       
        // Vorgegebene Werte im Speicher
        speicher[5]=7;
        speicher[6]=3;
       
        // Die etwas unelegante Programmeingabe
        programmspeicher.toLast();
        programmspeicher.insertBehind(2);
        programmspeicher.toLast();
        programmspeicher.insertBehind(5);
        programmspeicher.toLast();
        programmspeicher.insertBehind(3);
        programmspeicher.toLast();
        programmspeicher.insertBehind(6);
        programmspeicher.toLast();
        programmspeicher.insertBehind(4);
        programmspeicher.toLast();
        programmspeicher.insertBehind(6);
        programmspeicher.toLast();
        programmspeicher.insertBehind(5);
        programmspeicher.toLast();
        programmspeicher.insertBehind(0);
        programmspeicher.toLast();     
        programmspeicher.insertBehind(1);
       
    }
   
    public void run() {
         int zwischenspeicher;
        boolean stopflag=false;
        programmspeicher.toFirst();
        while (programmspeicher.isBehind()!=true && stopflag==false) {
            zwischenspeicher = (Integer) programmspeicher.getItem();
             System.out.println(zwischenspeicher);
            if (zwischenspeicher==1) stopflag=true;
            if (zwischenspeicher==2) addiereEins();
            if (zwischenspeicher==3) subtrahiereEins();
            if (zwischenspeicher==4) pruefeObNull();
            if (zwischenspeicher==5) springeAuf();
            programmspeicher.next();
         }
         }
    }
        else {
   
            System.out.println(liste.getItem()+"\n");  
    public void addiereEins() {
            liste.next();
        int adzwischen;
            rekursiveAusgabe();
        programmspeicher.next();
            System.out.println("*");
        adzwischen = (Integer) programmspeicher.getItem();
         }
         speicher[adzwischen]++;
     }
     }
</source>


    public void subtrahiereEins() {
{{Übung|
        int adzwischen;
* Vergleichen Sie die iterativen und rekursiven Fakultätsmethoden-Varianten. Übersetzen Sie den Pseudo-Code in Java.
        programmspeicher.next();
* Analysieren Sie die oben stehende Methode rekursiveAusgabe(). Gehen Sie dabei vor allem auch auf die Bildschirmausgabe der Sternchen ein.
        adzwischen = (Integer) programmspeicher.getItem();
* Recherchieren Sie nach weiteren Beispielen.
        speicher[adzwischen]--;
}}
    }
   
    public void pruefeObNull() {
        int adzwischen;
        programmspeicher.next();
        adzwischen = (Integer) programmspeicher.getItem();
        if (speicher[adzwischen]==0) {
            programmspeicher.next();
            programmspeicher.next();
        }
    }


    public void springeAuf() {
        int adzwischen;
        programmspeicher.next();
        adzwischen = (Integer) programmspeicher.getItem();
        programmspeicher.toFirst();
        for (int i=0;i<adzwischen;i++) programmspeicher.previous();
    }
   
    public void list() {
        int i=0;
        programmspeicher.toFirst();
        while (!programmspeicher.isBehind()) {
            System.out.println("Schritt:"+i+" - Befehl:"+(Integer) programmspeicher.getItem());
            programmspeicher.next();
            i++;
        }
        programmspeicher.toFirst();
    }
   
    public void zeigeSpeicher() {
        for (int i=0;i<10;i++) System.out.println("Zelle:"+i+" - Inhalt:"+speicher[i]);
    }
   
} // Ende der Klasse Modellrechner
</source>


[[Kategorie:Java]]
[[Kategorie:Java]]

Version vom 25. November 2009, 21:41 Uhr

Vorlage:Kurzinfo-3

Als Rekursion (auch Rekurrenz oder Rekursivität), von lateinisch recurrere entspr. zurücklaufen, bezeichnet man den Aufruf oder die Definition einer Funktion durch sich selbst. Die gegenseitige Rekursion bildet sich durch den gegenseitigen Verweis zweier oder mehrerer Funktionen auf einander.

In vielen Fällen ist die Rekursion eine von mehreren möglichen Problemlösungsstrategien, sie führt oft zu eleganten mathematischen Lösungen. In der Regel sind rekursive Programme (als Darstellung eines rekursiven Problems) zwar wesentlich kompakter (also kürzer) als die iterativen Varianten, dafür sind sie etwas langsamer und der Speicheraufwand ist höher.

Ohne geeignete Abbruchbedingung geraten solche rückbezüglichen Aufrufe in einen so genannten infiniten Regress (umgangssprachlich Endlosschleife). Zur Vermeidung von infinitem Regress insbesondere in Computerprogrammen bedient man sich der semantischen Verifikation von rekursiven Funktionen. Der Beweis, dass kein infiniter Regress vorliegt, wird dann zumeist mittels einer Schleifeninvariante geführt (siehe auch Invariante). Dieser Beweis ist allerdings nicht immer möglich (siehe Halteproblem).


Wikipedia-logo.png Rekursion, Wikipedia – Die freie Enzyklopädie, 21.11.2006 - Der Text ist unter der Lizenz „Creative Commons Attribution/Share Alike“ verfügbar; zusätzliche Bedingungen können anwendbar sein. Siehe die Nutzungsbedingungen für Einzelheiten. In der Wikipedia ist eine Liste der Autoren verfügbar.



Beispiel

Fakultät:
5! = 1 * 2 * 3 * 4 * 5

rekursiv

1 fakultät_rekursiv(n)
2 {
3   wenn n <= 1
4       dann return 1
5       sonst return ( n * fakultät_rekursiv(n-1) )
6 }

iterativ

1 fakultät_iterativ(n)
2 {
3     fakultät = 1
4     faktor = 2
5     solange faktor <= n
6     {
7         fakultät = fakultät * faktor
8         faktor = faktor + 1
9     }
10    return fakultät
11}


Listenausgabe

(Setzt Java/List o.ä. voraus)

    private void rekursiveAusgabe() {
        if (liste.isBehind()){
            System.out.println("Fertig.");
        }
        else {
            System.out.println(liste.getItem()+"\n"); 
            liste.next();
            rekursiveAusgabe();
            System.out.println("*");
        }
    }


Übung
  • Vergleichen Sie die iterativen und rekursiven Fakultätsmethoden-Varianten. Übersetzen Sie den Pseudo-Code in Java.
  • Analysieren Sie die oben stehende Methode rekursiveAusgabe(). Gehen Sie dabei vor allem auch auf die Bildschirmausgabe der Sternchen ein.
  • Recherchieren Sie nach weiteren Beispielen.