mikrocontroller.net

Forum: PC-Programmierung Ich komme nicht mehr aus meiner while schleife.


Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!

Ich versuche, eine While schleife zu programmieren, die so oft 
durchläuft bis zwei dreistellige Vektoren vom Typ double gleich sind.

Dazu habe ich die Bedinung so formuliert:

while (r[0] != v[0] || r[1] != v[1] ||  r[2] != v[2])
{
.....
}

Alle drei Komponenten müssen gleich sein.

Lass ich mir bei jedem Schleifendurchlauf beide Vektoren ausgeben, sind 
die auf die angezeigte Stellenanzahl bereits gleich, leider bricht die 
Schleife nicht ab.

Wie schaffe ich das, den Vergleich nur auf 6 Nachkommastellen genau 
anstellen zu lassen?


Vielen Dank für die Hilfe,

Grüße.

Patrick

Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Äh mist, Tausche || durch && , an der Stelle hab ich nur probiert, ob 
vllt. irgendeine der Komponenten ausreichend gleich wird.

Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, wenn ich alle Variablen als float deklariere, dann bricht die 
Schleife korrekt ab, die letzten Stellen sind aber zu ungenau.
Ich brauche die 6 Nachkommastellen.

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick schrieb:
> Wie schaffe ich das, den Vergleich nur auf 6 Nachkommastellen genau
> anstellen zu lassen?

Double oder Float auf Gleichheit zu prüfen ist nicht so toll.
Wie du schon gemerkt hast brauchst du eine kleine Abweichung, bei der du 
sagen kannst "und jetzt sind die Zahlen für praktische Zwecke gleich".

Am besten geht sowas über ein Intevall, z,b so
//Funktion abs liefert absoluten Betrag
const float intervall=0.01;

float a,b;
//irgendwie besetzen

if( abs(a-b) < intervall)
...

//falls a und b auf 0.01 gleich

:-)

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick schrieb:
> while (r[0] != v[0]

while ( (r[0] < v[0]-epsilon || r[0] > v[0]+epsilon ) ...

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Äh mist, Tausche || durch && , an der Stelle hab ich nur probiert, ob
vllt. irgendeine der Komponenten ausreichend gleich wird.

Huch? Für diese Beschreibung:

>eine While schleife zu programmieren, die so oft
>durchläuft bis zwei dreistellige Vektoren vom Typ double gleich sind

ist diese Formulierung durchaus angemessen.
while (r[0] != v[0] || r[1] != v[1] ||  r[2] != v[2])
{
.....
}

Falls die || durch && ersetzt werden, dann bricht die Schleife ab sobald 
eine der Vektorspalten gleich ist.


Aber Dein eigentliches Problem ist, das Du double Werte eben nur mit 
begrenzter Genauigkeit berechnen kannst und deswegen auch vergleichen. 
D.h. ein mathematischer Zusammenhang kann zwar eine Identität 
beschreiben, die tatsächliche Berechnung aber eben doch verschiedene 
Zahlen ergeben.

Es wäre gut, wenn Du mal den Anwendungsfall beschreibst.

Eine allgemeine Empfehlung wäre die Bedingung der Gleichheit dadurch zu 
ersetzen, das die Werte sich um mehr als ein gewisses Epsilon 
voneinander unterscheiden müssen um als ungleich bewertet zu werden.

Autor: Orakel von Delphi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Drei von Drei ist schon mal nicht schlecht.

Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Floh schrieb:
> //Funktion abs liefert absoluten Betrag
> const float intervall=0.01;
>
> float a,b;
> //irgendwie besetzen
>
> if( abs(a-b) < intervall)
> ...
>
> //falls a und b auf 0.01 gleich

So hab ichs jetzt gemacht, funktioniert wunderbar :D
Vielen Dank für den Tipp!
Stand ich jetzt wirklich auf dem Schlauch :D

Wirklich? || statt && ? Aber && wird doch nur "true" wenn alle drei 
Bedingungen erfüllt sind? Oder hab ichs vertauscht?

Der Anwendungsfall ist zu einer 3x3 Matrix einen stationären Vektor zu 
finden. Ist eine Übungsaufgabe für die Uni, deswegen hab ich den ganzen 
Code nicht reingestellt ;)
Also durch wiederholtes ausführen von r= M*r (mit M = Matrix, r=Vektor), 
bis sich r nicht mehr ändert.
Gibt wahrscheinlich eine geschicktere Lösung als meine, ist etwas 
länglicher geworden - naja - übung macht den Meister.

Danke für die Hilfe!

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick schrieb:
> Aber && wird doch nur "true" wenn alle drei
> Bedingungen erfüllt sind?

genauso isses,
aber du willst ja die Schleife solange ausführen lassen, solange noch 
eine Komponente nicht gleich,
also solange x1!=x2 oder y1!=y2 oder z1!=z2
und oder ist nun mal ||

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wirklich? || statt && ? Aber && wird doch nur "true" wenn alle drei
>Bedingungen erfüllt sind? Oder hab ichs vertauscht?

Lassen wir mal das Epsilon weg und nehmen den ursprünglichen Code:
while (r[0] != v[0] || r[1] != v[1] ||  r[2] != v[2])
{
.....
}

Du hast geschrieben, dass : "...While schleife zu programmieren, die so 
oft
durchläuft bis zwei dreistellige Vektoren vom Typ double gleich sind."

In der obigen Formulierung wird die Schleife solange wiederholt, wie nur 
irgendeines der r[n] != v[n]. D.h. umgekehrt, erst wenn alle r[n] == 
v[n], dann bricht die Schleife ab.

Ersetzt Du aber die || durch &&,:
while (r[0] != v[0] && r[1] != v[1] && r[2] != v[2])
{
.....
}

Dann läuft die Schleife nur solange wie alle r[n] != v[n]. Sobald nur 
irgendeines der r[n] = v[n] ist bricht die Schleife ab. Das aber stimmt 
nicht mit der obigen Forderung überein.

>Aber && wird doch nur "true" wenn alle drei
>Bedingungen erfüllt sind

Das ist aber hier noch in Beziehung zu setzen mit der Wirkung der 
Bedingung des while-Befehles. Der läuft nämlich solange die Bedingung 
wahr ist. Da aber erst der Schleifenkörper den Wunschzustand herstellt 
muss die Schleife ausgeführt werden solange der Wunschzustand nicht 
besteht. Der Wunschzustand besteht aber nicht, wenn irgendeiner der r[n] 
!= v[n], was vollständig eben so: "(r[0] != v[0] || r[1] != v[1] || 
r[2] != v[2])" ausgedrückst wird.

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...ausgedrückst wird.

Das habe ich aber schön geschrieben.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Floh schrieb:
> Patrick schrieb:
>> Wie schaffe ich das, den Vergleich nur auf 6 Nachkommastellen genau
>> anstellen zu lassen?
>
> Double oder Float auf Gleichheit zu prüfen ist nicht so toll.
> Wie du schon gemerkt hast brauchst du eine kleine Abweichung, bei der du
> sagen kannst "und jetzt sind die Zahlen für praktische Zwecke gleich".
>
> Am besten geht sowas über ein Intevall, z,b so
>
>
> //Funktion abs liefert absoluten Betrag
> const float intervall=0.01;
> 
> float a,b;
> //irgendwie besetzen
> 
> if( abs(a-b) < intervall)
> ...
> 
> //falls a und b auf 0.01 gleich
> 
> 
> :-)

abs() liefert aber nur einen Absolutbetrag einer ganzen Zahl,
in diesem Fall also komplett ohne Nachkommastellen.
Du meinst wohl fabs()?
Außerdem will er doch double vergleichen.
Dann könnte man intervall auch gleich double machen, es wird
ja ohnehin zu double konvertiert.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick schrieb:
> Gibt wahrscheinlich eine geschicktere Lösung als meine
Wenn sie das Problem in ausreichender zeit löst wieso nicht? Ich würde 
aber in so einem Fall noch eine maximale Iterationszahl vorsehen, z.B. 
nach 100'000 Durchläufen abbrechen, und dann den User darauf hinweisen 
das abgebrochen wurde und das Ergebnis ggf. nicht verlässlich/genau ist 
das ist besser als wenn das Programm sich "aufhängt" (gerade zum 
testen).

Das deckt dann auch den Fall ab, das es ggf. gar keine Lösung gibt, oder 
die Lösung numerisch instabil ist.

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Du meinst wohl fabs()?

Wahrscheinlich :-)
So Sachen schreib ich eigentlich immer kurz in mein Programm rein, geht 
schneller als nach der include zu suchen :-)
double fabs(double v)
{
  if(v <0)
    v *= -1;
  return v;
}

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick schrieb:

> while (r[0] != v[0] || r[1] != v[1] ||  r[2] != v[2])

Man darf das auch so formulieren, evtl. verständlicher:

while (!(r[0] == v[0] && r[1] == v[1] && r[2] == v[2]))

Autor: M. B. (manubaum) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Finde ich auch besser, funkioniert übrigens immer gleich mit dem 
umwandlen von boolschen Ausdrücken:
http://de.wikipedia.org/wiki/De_Morgansche_Gesetze

Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi !

Also irgendwie gibt es bei dem Programm doch Probleme.
Ich habe jetzt das gleiche Problem mit einem Lösungsansatz über "for" 
schleifen geschrieben.
Dieser schafft den Abbruch mit der gleichen Bedingung wie oben, bzw. der 
verbesserten: !(r[0] == v[0] && r[1] == v[1] && r[2] == v[2]) .
Hatte da wirklich nen Denkfehler, || war schon richtig, && hatte ich zum 
testen genommen.


Irgendwas stimmt an meinem ersten Programm nicht, und ich würde wirklich 
gerne wissen was.

Hätte jemand mal Zeit und Lust, über die paar Zeilen drüberzuschauen? 
Leider müsste ich das per e-mail verschicken, sonst gibts bei der Abgabe 
u.U. probleme wie "du hast es ja aus dem Netz gezogen".


Ansonsten hab ich ja jetzt eine funktionierende Lösung. Mir gefällt zwar 
die while schleife besser, aber das for ist auch o.k.

Danke und viele Grüße,

Patrick

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und jetzt sollen wir uns das akuelle Programm irgendwie
metaphysisch einblenden und darin Fehler suchen?

Autor: Gerry E. (micky01)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Patrick schrieb:
> Hätte jemand mal Zeit und Lust, über die paar Zeilen drüberzuschauen?
> Leider müsste ich das per e-mail verschicken, sonst gibts bei der Abgabe
> u.U. probleme wie "du hast es ja aus dem Netz gezogen".
>
>
> Ansonsten hab ich ja jetzt eine funktionierende Lösung. Mir gefällt zwar
> die while schleife besser, aber das for ist auch o.k.

Naja, in C zumindest sind for und while äquivalent.
for ist nur eine Abkürzung für while!

Die Abbruchbedingung ist entscheidend, und wenn Du die hast, so kommst 
Du sowohl aus der while wie auch aus der for Schleife immer raus.

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gerry E. schrieb:
> Patrick schrieb:

> Die Abbruchbedingung ist entscheidend, und wenn Du die hast, so kommst
> Du sowohl aus der while wie auch aus der for Schleife immer raus.

Angesichts der Schwierigkeiten, die der TO damit hatte, zu entscheiden 
ob && oder ||, aber auch aus allgemeinen Überlegungen heraus, müsste man 
eigentlich, zumindest gegenüber Anfängern, eher vermeiden von 
"Abbruchbedingungen" zu sprechen, denn die Bedingung in for oder 
while-Schleifen sorgt gerade dann dafür, dass die Schleifer weiter 
bzw. nochmals durchlaufen wird, wenn sie wahr ist.

Hingegen scheint es mir einleuchtend zu sein wenn man intuitiv annimt, 
dass "Abbruchbedingungen" wahr sein müssen, damit sie eine Abbruch, hier 
also ein Verlassen der Schleife bewirken.

Hoffe das ist hilfreich.

Autor: Patrick K. (unknown_artist)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So jetzt hab ich das Pwd. wieder:

Also ich wollte das ja nicht öffentlich hier reinschreiben, wegen der 
Abgabe, deswegen hatte ich den Vorschlag mit der e-mail gemacht. Die 
sind recht hart, was Plagiatsfälle betrifft.

Ich werde jetzt die sowieso funktionierende Lösung abgeben, deswegen 
häng ich die nicht funktionsfähige while-Lösung mal an, damit Google das 
auch nicht gleich findet.
Hoffe, ich hab das ausreichend kommentiert.

Es sind noch viele "Testausgaben" mit eingebaut (dementsprechend 
Markiert) die das ganze noch etwas länger aussehen lassen als es ist.

Hoffe jemand findet meinen Fehler :D

Vielen Dank fürs helfen!

Patrick


EDIT: Ich kann nichts hochladen? Dann eben hier :
http://nopaste.info/e78cc3b7a2.html

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Huch schrieb:
> ... eher vermeiden von "Abbruchbedingungen" zu sprechen ...

Stimmt irgendwo - habe ich mir noch nie überlegt, daß man
damit Probleme haben kann.

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weisst Du Patrick, Deine Fehler im Programm musst Du Dir schon selber 
suchen. Das sind ja die inhärenten Annahmen, das Du nicht nur Programme 
schreibst sondern auch Fehler suchst, Deinen Entwurf mit dem 
tatsächlichen Verhalten vergleichst uswusf.

Bei deinem ersten Posting war halt jedem Praktiker klar das Vergleich 
von double-Variablen so Tücken hat. An sich hättest Du durch 
analytisches (wissenschaftliches) selbst darauf kommen müssen das ein 
einzelner Vergleich hier schief geht obwohl die Zahlenwerte gleich sein 
"sollten". Wenn Du an dieser Stelle nachgefragt hättest wäre unsere 
plausible Vermutung vorweggenommen, aber mehr Eigeninitiative von Dir 
gezeigt.

Ein weitere analytischer Schritt wäre gewesen, festzustellen, ob zwei 
Werte von denen Du annimmst, das sie identisch sind, auch auf anderem 
Weg als mit dem "==" bzw. "!=" als identisch zu beurteilen sind. Dann 
hättest Du festgestellt, das es gewisse Abweichungen im Bitmuster gibt, 
obwohl die Ausgabe innerhalb von 6 Stellen nach dem Komma identisch ist 
(oder auch nicht).

Das hätte Dich zu der obigen These geführt, das eine mathematische 
Identität, praktisch ausgeführt dennoch zu unterschiedlichen Resultaten 
führen kann. Das aber zu Rundungsproblemen, Zahlendarstellung etc.

So! Abgesehen davon, das Du ausser "geht nicht" garnicht geschrieben 
hast, was das Problem ist, ist es gerade das was Du im Studium lernen 
sollst. Analytisches Arbeiten, folgerichtiges Denken.

Mach das mal selbst. Ich übe selber noch.

Autor: Patrick K. (unknown_artist)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aha.

Herzlichen Dank auch für diese Belehrung. Meine Studienziele waren mir 
noch nie so klar. Was soll denn so eine arrogante Art?
Statt jetzt einfach das funktionierende abzugeben und es dabei zu 
belassen bastel ich trotzdem weiter an dem alten rum, weil ich nicht 
verstehe warum das auf diesem weg nicht funktioniert.

Und du hast sicher nie irgendjemanden gefragt, als du noch am Anfang 
standest und irgendwas nicht funktioniert hat? Alles immer nur 
selfmade-Männer hier in diesem Forum. War doch ein Fehler, hier zu 
fragen.

Mir ist völlig bewusst, warum ich bei dieser  Annährung mit dem direkten 
Vergleich von double auf Probleme stoße. War es mir auch schon vorher.

Ich meine, zwei verschiedene Lösungsansätze zu schreiben, von denen 
einer zum Erfolg führt und der andere nur knapp, ist prinzipiell schon 
mindestens mit "ausreichend" an Eigeninitiative zu bewerten.

Mit der gleich definierten Bedingung funktioniert das eine, aber das 
andere nicht, obwohl es zwischen for und while keinen ersichtlichen 
Unterschied gibt.

Ich habe nicht gesagt "funzt nicht", sondern mein Problem ist klipp und 
klar formuliert: Er geht nicht aus der while schleife, obwohl er die 
gleiche Bedingung bei FOR akzeptiert.

Warum funktioniert das bei for, und nicht bei while?


Falls mir doch noch jemand weiterhelfen kann, wäre ich weiterhin 
dankbar. Sollte noch irgendjemand den Drang verspüren seine 
Hobbypädagogik an den Mann zu bringen, mein Bedarf ist gedeckt!

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bedaure Dich, ohne Deine ausdrückliche Aufforderung über Denk- und 
Arbeitsweise bzw. Art der Frageformulierung sowie die Situation belehrt 
zu haben. Ich hoffe Du verzeihst mir, kann jedoch auch damit leben wenn 
Du es nicht tust.

Viel Erfolg noch.

Autor: irgendwer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähm,
also aus der Erfahrung heraus anderen Studenten Java und C beizubringen, 
kann es eben am Anfang passieren, dass man vergisst die Laufvariable zu 
in/dekrementieren. Evtl. liegt es daran. Da du ja anscheinend eine 
for-Schleife nutzt (gut man kann sie auch geschickter nutzen, um ohne 
Laufvariable nutzen nutzen zu müssen) und auch den selben Code innerhalb 
der Schleifen hast (?), wäre es ein Blick Wert. Anders kann ich mir ohne 
den Code zu sehen - und das muss man nicht unbedingt für ne Ferndiagnose 
, aber hilfreich schon - nicht eklären. Und wir sind alle etwas faul... 
also wäre's angebracht wenigstens den allgemein gehaltenen Pseudo-Code 
für den Inhalt der Schleife (wenn er denn so geheim ist) zu posten, denn 
hier hilft man sich freiwillig und nicht weil man muss.
Viel Erfolg noch!
Irgendein HiWi

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.