Benutzer mit den meisten Antworten
Warum funktioniert mein MethodInvoker nicht?

Frage
-
Hi Zusammen,
habe eine kurze aber für mich wichtige Verständnisfrage:
Warum funktioniert folgend mein MethodInvoker nicht?
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace GPI13_4_Fibonacci { public partial class frmFibonacci : Form { long[] werte = new long[93]; long wert; const string berechnen = "Berechnen"; public frmFibonacci() { InitializeComponent(); } private void cmdSchließen_Click(object sender, EventArgs e) { Environment.Exit(0); } private void cmdBerechnen_Click(object sender, EventArgs e) { Thread t2 = new Thread(new ThreadStart(this.ZahlAusgeben)); if (cmdBerechnen.Text == berechnen) { cmdBerechnen.Text = "Abbrechen"; if (long.TryParse(tbEingabe.Text, out wert) && long.Parse(tbEingabe.Text) > 0 && long.Parse(tbEingabe.Text) < 93) t2.Start(); else MessageBox.Show("Ungültige Eingabe!", "Fehler!", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { cmdBerechnen.Text = berechnen; t2.Abort(); } tbEingabe.SelectAll(); tbEingabe.Focus(); } public long fibZahl(long z) { lock (this) { if (z == 1 || z == 2) { werte[0] = 1; werte[1] = 1; return 1; } else werte[z - 1] = fibZahl(z - 1) + fibZahl(z - 2); return werte[z - 1]; } } public void ZahlErrechnen() { long wert = fibZahl(92); } public void ZahlAusgeben() { while (true) { if (werte[wert] != 0) { MessageBox.Show("Die " + wert + ". Fibonacci-Zahl lautet: " + werte[wert], "Fertig!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); MethodInvoker buttonUpdate = delegate { cmdBerechnen.Text = berechnen; }; Invoke(buttonUpdate); break; } } } private void frmFibonacci_Load(object sender, EventArgs e) { Thread t = new Thread(new ThreadStart(this.ZahlErrechnen)); t.Start(); } private void frmFibonacci_FormClosing(object sender, FormClosingEventArgs e) { Environment.Exit(0); } } }
Freue mich sehr auf eure Antworten.
Gruß
Matze
Antworten
-
Hi Iso7,
die Methode "ZahlErrechnen" terminiert bei mir nicht wegen der Rekursion "werte[z -1] = fibZahl(z -1) + fibZahl(z -2);". Damit die Methode terminiert, sollte sie z.B. so aussehen:public long fibZahl(long z) { lock (this) { if (z == 1 || z == 2) { werte[0] = 1; werte[1] = 1; return 1; } else if (werte[z - 2] == 0 || werte[z - 3] == 0) werte[z - 1] = fibZahl(z - 1) + fibZahl(z - 2); else werte[z - 1] = werte[z - 2] + werte[z - 3]; return werte[z - 1]; } }
Einfacher geht es aber so:
public long fibZahl(long z) { if (z > 1) werte[z - 1] = fibZahl(z - 1); if (z == 1 || z == 2) return 1; return werte[z - 1] + werte[z - 2]; }
wobei noch zu klären ist, ab der erste Wert im Array werte auf Index 0 oder Index 1 steht. Im obigen Beispiel steht er auf Index 1.
--
Viele Grüsse
Peter Fleischer (MVP, Partner)
Meine Homepage mit Tipps und Tricks
- Bearbeitet Peter Fleischer Mittwoch, 15. Juli 2015 06:26 verkürzte rekursive Methode
- Als Antwort markiert Idhaun Donnerstag, 16. Juli 2015 09:03
-
Hallo Matze,
weil Du den Text von Schaltfläche änderst, versuch mal die Invoke-Methode von Button aufzurufen:
cmdBerechnen.Invoke(buttonUpdate);
oder
cmdBerechnen.BeginInvoke(buttonUpdate);
Ich würde Dir empfehlen die Methode fibZahl zu überarbeiten (wie Peter vorgeschlagen hat). Ich vermute, dass der Prozess stark mit der Berechnung von Fibonacci Zahlen beschäftigt ist und deswegen der Text der Schaltfläche wird nicht geändert.
Grüße,
Alle Antworten
-
Hi,
die Rekursion in fibZahl ist unendlich. Die Funktion hat kein Ende. Das solltest Du erst einmal ändern, z.B. mit einem Testprojekt und Test der Funktion.--
Viele Grüsse
Peter Fleischer (MVP, Partner)
Meine Homepage mit Tipps und Tricks -
Hallo,
@Peter
ich sehe keine unendliche Schleife in der Methode fibZahl. Bei z ==2 wird die Rekursion beendet.
Aber es gibt einen Deadlock in dieser Methode (wegen lock(this)) und fehlt eine Prüfung, ob z <=0 ist.
@Matze
Wenn das Array werte[] wegen Deadlock in fibZahl(..) mit den Werten nicht gefüllt wird, dann hast Du unendliche Schleife in der Methode ZahlAusgeben().
Was ist cmdBerechnen? Wird der MessageBox angezeigt?
Änderung:
Es gibt keinen Deadlock bei diese Rekursion. Bei lock werden nur die andere Thread blockiert. Mein Fehler.
Grüße
- Bearbeitet Iso7 Donnerstag, 16. Juli 2015 08:56
-
Hi Iso7,
die Methode "ZahlErrechnen" terminiert bei mir nicht wegen der Rekursion "werte[z -1] = fibZahl(z -1) + fibZahl(z -2);". Damit die Methode terminiert, sollte sie z.B. so aussehen:public long fibZahl(long z) { lock (this) { if (z == 1 || z == 2) { werte[0] = 1; werte[1] = 1; return 1; } else if (werte[z - 2] == 0 || werte[z - 3] == 0) werte[z - 1] = fibZahl(z - 1) + fibZahl(z - 2); else werte[z - 1] = werte[z - 2] + werte[z - 3]; return werte[z - 1]; } }
Einfacher geht es aber so:
public long fibZahl(long z) { if (z > 1) werte[z - 1] = fibZahl(z - 1); if (z == 1 || z == 2) return 1; return werte[z - 1] + werte[z - 2]; }
wobei noch zu klären ist, ab der erste Wert im Array werte auf Index 0 oder Index 1 steht. Im obigen Beispiel steht er auf Index 1.
--
Viele Grüsse
Peter Fleischer (MVP, Partner)
Meine Homepage mit Tipps und Tricks
- Bearbeitet Peter Fleischer Mittwoch, 15. Juli 2015 06:26 verkürzte rekursive Methode
- Als Antwort markiert Idhaun Donnerstag, 16. Juli 2015 09:03
-
Hallo Peter,
ja, die Implementierung in der fibZahl(..) von Matze ist keine gute Lösung für die Fibonacci- Berechnung. Der Wert wird immer neu berechnet anstatt den Wert, der schon berechnet wurde, aus dem Array zu nehmen. Das führt zu der langen Berechnungszeit oder sogar zum Stack-Overflow. Ich habe extra diese Methode fibZahl(..) bei mir ausprobiert und die Methode wird bei mir terminiert. Ich habe kleine Werte (10-30) für den Test genommen. Mit dem Wert 93 dauert die Berechnung zu lange.
Grüße
- Bearbeitet Iso7 Mittwoch, 15. Juli 2015 09:19
-
Hi Ante,
Jo Danke das ist korrekt. Ich hatte die Variable "wert" zuvor innerhalb einer Methode deklariert weshalb ich sie in dieser Methode zunächst erneut deklarieren musste. Das fällt jetzt aber durch die globale Deklaration weg. Hab ich nicht aufgepasst.
@alle: Ich werde mich heute nachmittag ca 15 Uhr MESZ Uhr nochmal dran setzen und eure vorschläge testen. Auf jeden Fall schon einmal vielen Dank vorab für die große Resonanz.
Ich melde mich noch mal
Gruß
Matze
-
Die Methode ZahlErrechnen hat einen Fehler. Der Wert wert soll nicht wiedererklärt sein.
public void ZahlErrechnen() { wert = fibZahl(92); // Entfern den Wort long. }
Wenn man das Programm so ändert, dann muss auch die Mathode ZahlAusgeben() bearbeitet werden. Sonst kriegt man eine IndexOutOfRangeException.
- Bearbeitet Iso7 Mittwoch, 15. Juli 2015 08:25
-
Hi Iso7,
im vorliegenden Programm wird ein Array "werte" im Load-Ereignis erstellt, aus dem die Zahlen gelesen werden können. Es ist nicht notwendig, jedes Mal neu zu berechnen, was im Programm auch nicht gemacht wird.--
Viele Grüsse
Peter Fleischer (MVP, Partner)
Meine Homepage mit Tipps und Tricks -
Hi zusammen,
vielleicht noch eine kurze Info:
Rekursive Aufrufe halte ich auch für unsinnig. Allerdings ist das laut Aufgabenstellung so vorgesehen um eine längere abbrechbare Rechenlaufzeit zu erhalten.
Der Aufruf im Berechnungs-Thread muss nicht zwingend Terminieren. Das Widerspricht zwar den Regeln eines Algorithmus aber ist ebenso vorgegeben. Es Terminiert praktisch mit beendigung des Programmes Environment.Exit(0)
Ich hatte jetzt gedacht meins Terminiert bei der 92. Fibonacci-Zahl. Das ist die Zahl, die noch in den Typ Long passt.
Mich würde nach wie vor hauptsächlich interessieren warum mein MethodInvoker nicht funktioniert.
Leider bin ich noch nicht am heimischen PC und ich bekomme von hier auch keine VPN hin sodass ich noch nicht am Quellcode arbeiten kann. Aber schon mal vielen Dank für eure Antworten.
Ich bin überwältigt wie groß das Interesse an der Lösung dieser Aufgabenstellung ist :-)
Gruß
Matze
-
Hallo Matze,
weil Du den Text von Schaltfläche änderst, versuch mal die Invoke-Methode von Button aufzurufen:
cmdBerechnen.Invoke(buttonUpdate);
oder
cmdBerechnen.BeginInvoke(buttonUpdate);
Ich würde Dir empfehlen die Methode fibZahl zu überarbeiten (wie Peter vorgeschlagen hat). Ich vermute, dass der Prozess stark mit der Berechnung von Fibonacci Zahlen beschäftigt ist und deswegen der Text der Schaltfläche wird nicht geändert.
Grüße,