While-Schleife Endet zu früh



  • Hallo,

    wie schon im Titel beschrieben habe ich ein kleines Problem mit meiner while schleife, welche für mich momentan Grundlos abbricht.
    Bis jetzt konnte ich lediglich Feststellen, dass es ab einer bestimmten größe der Variablen "width" auftritt.

    Bekannte Werte für eine Fehlfunktion sind:

    increase = 0.0182149
    xMin = -10
    xMax = 10

    umgerechnet sollten dies ca. 1100 Schleifendurchläufe sein jedoch endet es schon bei ca der Hälfte. Würde mich freuen wenn mir jemand Helfen könnte

    MfG Gobbles

    increse = Math.Round((xMax - xMin) / width, 7);
    myPoints = new Point[4, (int)((xMax - xMin) / increse)+1];
    
    double i = xMin;
    int j = 0;
    string VarX = "";
        while (i <= xMax){
           //....
           //....
           //....
           i += increse;                               
        }
    


  • Hi ich nochmal
    nach stundenlangem Debuggen konnte ich den Fehler selbst herausfinden.
    Leider weiß ich nicht wie ich diesen umgehen kann.
    Das Problem liegt darin, dass in meinem Testfall beim Erhöhen von i + 0.0182149 ab einem gewissen Schleifendurchgang
    der Fall eintritt, dass i zu 1.99E-05 wird was nicht passieren sollte ein 0.000199 würde das ganze schon lösen.
    Meine Frage ist also nun nur noch kann ich es Verhindern das es eigenständig die Zahl in das E-Format kloppt?

    greez Gobbles



  • Warum ist varX denn ein string?



  • int count = 0;
    while (i <= xMax)
    {
        count++;
        i += increse;
    }
    Console.Write("Count: " + count);
    

    Gibt 1099 aus, wenn man die Rundung bedenkt ist das doch ein gutes Ergebnis ?

    Die Umwandlung ins "E-Format" macht VisualStudios Debugger automatisch, aber deswegen liegt es doch im Speicher nicht anders vor ?
    Bei der Umwandlung in einen string (was du aber in dem gezeigten Code ja nicht machst), kann man angeben wie die Zahl formatiert werden soll.

    Der Code den zu gepostet hast funktioniert, also erklär bitte nochmal wo das Problem liegt, oder poste den richtigen Code.



  • Ja, der Scheiß hat mich auch ein paar Tage gekosten.

    Bei .NET tauche bei Double immer wieder Rundungsfehler bei hohen Dezimalstellen auf.
    Das schreiben die in Ihrer Technical Note, aber stellen es nicht ab. 🙄
    http://msdn.microsoft.com/de-de/library/system.math.round(v=vs.110).aspx#Precision

    http://msdn.microsoft.com/de-de/library/wyk4d9cy(v=vs.110).aspx

    Meine Erfahrung ist, dass Round bis zwei Stellen hintern Komma noch stabil.



  • @Prof84
    Rundungsfehler sind ja hier nicht das Problem. Wegen eines Rundungsfehlers bei Math.Round wird die Schleife ja nicht nur halb so oft ausgeführt.

    Wir haben hier einfach nicht den Code den der TS auch wirklich verwendet. Oder die Messung der Schleifendurchläufe des TS ist falsch.



  • Prof84 schrieb:

    Ja, der Scheiß hat mich auch ein paar Tage gekosten.
    Bei .NET tauche bei Double immer wieder Rundungsfehler bei hohen Dezimalstellen auf.
    Das schreiben die in Ihrer Technical Note, aber stellen es nicht ab. 🙄

    loooooool
    Schade um die zwei Tage. Hättest http://de.wikipedia.org/wiki/IEEE_754 lesen sollen.

    Prof84 schrieb:

    Meine Erfahrung ist, dass Round bis zwei Stellen hintern Komma noch stabil.

    loooooool
    Ja klar, weil 0.999==1 wenn man zweistellig anzeigt.



  • So um das ganze zu lösen hier etwas mehr Kontext.

    Das Ganze Programm wird ein Graphischer-Taschenrechner und in der Funktion, werden die Punkte des Funktion die zu Zeichnen ist Berechnet. Durch die Umwandlung ins E-Format hat ist ein Fehler in der Berechnung ergeben und der Code wurde Vorzeitig jedoch ohne Fehler beendet. Zur Lösung des Problems noch etwas mehr Code...

    increse = Math.Round((xMax - xMin) / width, 7);
    myPoints = new Point[4, (int)((xMax - xMin) / increse)+1];
    
    double i = xMin;
    int j = 0;
    string VarX = "";
         while (i <= xMax) //tbRangeEnd
         {
             if (Funk1 != "")
             {
                  i = Math.Round(i, 7);;
                  VarX = i.ToString("F10");
                  string Term = Funk1;
                  Mathlogic myMath = new Mathlogic(Term.Replace("X", VarX));
                  myPoints[0, j].Y = dblY_X -Math.Round(Convert.ToDouble(myMath.getErgebnis()), 15) * dblPitchPixelY / pitch);
                  myPoints[0, j].X = dblX_Y + Math.Round(i,15)*dblPitchPixelX/pitch;
    
              }
              if (Funk1 != "")
              {
                  drawPoints(0);
              }
    }
    


  • Gobbles schrieb:

    Durch die Umwandlung ins E-Format hat ist ein Fehler in der Berechnung ergeben und der Code wurde Vorzeitig jedoch ohne Fehler beendet.

    Nein. Da ist nirgends eine Umwandlung ergo auch kein Fehler der dazu führt dass die Schleife zu früh abbricht.



  • Die Schleifenbedingung hängt nur von i und xMax ab, also solltest du uns alles zeigen, was damit zu tun hat. Die irrelevanten Teil darfst du dagegen gerne weglassen.



  • Natürlich entstand eine Umwandlung in das E-Format und zwar wenn i lim -> 0 kam es irgendwann dazu das i = 1.99E-05 wurde.
    dabei wurde der Term x^2 zu 1.99E-05 da meine Klasse Mathlogic aber damit nichts anfangen konnte lief was falsch.
    Warum diese aber keinen Error dabei ausgegeben hat wundert mich da wenn ich 1.99E-05^2 per Hand berechnen lasse
    es mir einen Fehler meldet das ich 1.99E nicht in double Umwandeln kann was ja auch logisch erscheint

    das ändern von
    VarX = i.ToString();
    zu
    VarX = i.ToString("F10");
    hat das Problem beseitigt da nun kein E-Format in dem Term-String landet

    PS: Alles was mit der Schleife und deren Bedinungen verknüpft ist ist bereits in dem Code enthalten das Problem lag an meiner Klasse Mathlogic diese zu Posten würde aber glaube jeglichen Rahmen sprengen -.-



  • Deine Erklärung ergibt irgendwie keinen Sinn, aber gut, wenns geholfen hat :p

    Gobbles schrieb:

    PS: Alles was mit der Schleife und deren Bedinungen verknüpft ist ist bereits in dem Code enthalten

    Nein, man kann aus dem Code nicht Wert und Typ von xMax ablesen, auch von xMin und increse [sic] nicht. Das Inkrement hast du bei der zweiten Variante, die angeblich vollständiger sein sollte, sogar weggelöscht.



  • Siehe ersten Beitrag 🙂

    increase = 0.0182149
    xMin = -10
    xMax = 10

    oh ja das fehlt natürlich so sollte es eigentlich aussehen 🙂

    increse = Math.Round((xMax - xMin) / width, 7); 
    myPoints = new Point[4, (int)((xMax - xMin) / increse)+1]; 
    
    double i = xMin; 
    int j = 0; 
    string VarX = ""; 
         while (i <= xMax) //tbRangeEnd 
         { 
             if (Funk1 != "") 
             { 
                  i = Math.Round(i, 7);; 
                  VarX = i.ToString("F10"); 
                  string Term = Funk1; 
                  Mathlogic myMath = new Mathlogic(Term.Replace("X", VarX)); 
                  myPoints[0, j].Y = dblY_X -Math.Round(Convert.ToDouble(myMath.getErgebnis()), 15) * dblPitchPixelY / pitch); 
                  myPoints[0, j].X = dblX_Y + Math.Round(i,15)*dblPitchPixelX/pitch; 
    
              } 
              j++;
              i += increse; 
         }
         if (Funk1 != "") 
         { 
              drawPoints(0); 
          } 
    }
    


  • jetzt fehlt immernoch der typ, auch wenn das wohl 3 mal double sein wird



  • KN4CK3R schrieb:

    jetzt fehlt immernoch der typ, auch wenn das wohl 3 mal double sein wird

    ja alle 3 in double auch mit decimal schon getestet mit gleichem Problem aber wie gesagt mit der toString("F20") funktioniert es nun Tadellos



  • richtig lösen würdest du dein problem wahrscheinlich wenn du einen int für die schleife nehmen würdest und den double wert dann jedes mal berechnest



  • KN4CK3R schrieb:

    richtig lösen würdest du dein problem wahrscheinlich wenn du einen int für die schleife nehmen würdest und den double wert dann jedes mal berechnest

    Und falsch lösen indem du den Code verwendest den du hier gepostet hast. 🤡
    An double liegt das nicht, so schlimm sind die Rundungsfehler nun auch wieder nicht.

    Gehen wirs mal anders an: Wie kommst du denn darauf dass die Schleife nicht oft genug ausgführt wird ?
    Kann das nchct auch ein Problem in der Zeichenlogik sein - oder hast du das wirklich nachgeprüft ?



  • Danke für die idee ich werde es gleich mal versuchen.
    Der Schleifenabbruch entstand wie schon erwähnt jedoch durch die Übergabe eines Termes an meine Mathlogic der ein E-Format beinhaltet, das Seltsame dran war nur das er mir keinen Fehler ausgegeben hat, was eigentlich passieren sollte. Zumindest tut es dies, wenn ich nur einen Wert mit einem E-Format berechnen lasse



  • So Funktion wurde umgeschrieben jedoch mit dem selben Problem.
    Bei einem Test hatte ich das selbe Problem das ich ab einem Bestimmten Punkt nahe 0 ein E-Format erhatlen habe.
    Die Ausgabe der Messagebox war:

    VarX = -1.989999999998506E-05 j = 549 increse = 0.0182149

    xMax = 10.0 (double)
    xMin = -10.0 (double)
    width = 1098 (double)

    double increse = Math.Round((xMax - xMin) / width, 7); 
    Points[,] myPoints = new Point[4, (int)((xMax - xMin) / increse)+1];
    int j = 0;
    string VarX;
    
    while(j < myPoints.Length/4)
       {
       // i = Math.Round(i, 7); ;
       // VarX = i.ToString("F20");
       VarX = (xMin + (j * increse)).ToString();
       if (VarX.Contains('E'))
          {
             MessageBox.Show("VarX = " + VarX + " j = " + j.ToString() + " increse = " +increse.ToString());
          }
          j++;
       }
    


  • E Format (aka scientific notation) vermeidet man z.B. mit Formatstrings:

    number.ToString("F9"); //9 decimals fixedpoint
    

    Wobei das gar nicht das Problem ist, das eigentliche Problem ist dein Design. Ein Taschenrechner sollte NIE einen string zum Rechnen brauchen!
    Ausgabe ist ok, aber nicht zur Berechnung deines Terms.
    Und bei der Ausgabe kannst du die wissenschaftliche Notation verwenden, oder eine Lösung von Stackoverflow: Double to string conversion without scientific notation nutzen.


Anmelden zum Antworten