Rundungsfehler in eigener Funktion



  • Hallo,

    schreibe im Moment an nem MatheProgramm für meine facharbeit der Jgst. 12.
    Ich weiß, es ist kein ANSI C++, ich muss halt nen Array aus Punkten den ich von der Maus empfange mit Linien verbinden, undzwar halt genau so wie die GDI das macht(Bsp: Auch Paint empfängt halt nur einzelne Punkte, verbindet diese aber untereinander mit Linien!).

    So, ich mache das jetzt halt mit Steigungsdreieck, etc, die Ergebnisse sind auch zu 98% wirklich gut, bin auch froh dass ich das bis jetzt schon geschafft habe, aber für ne Mathe Facharbeit sollten es schon 100% Richtigheit sein 😃

    Also, mein Fehler liegt in der von mir selbst geschriebenen Rundungsfunktion für Floats, und das ist halt mein ANSI-C++ Problem 🙂 :

    int round(float value)
    {
    	float rest=value-int(value);
    
    	if(rest==0.500000)
    		return int(value+0.5f);
    	else if(rest<0.500000)
    		return int(value-rest);
    	else
    		return int(value+(1-rest));
    
    }
    

    Soll heißen, die Funktion soll als Rundungsgrenze 0.5 nehmen. Kennt ihr sicher, Beispiele dafür :
    x.3 -> x
    x.49 -> x
    x.5 -> x+1
    x.8 -> x+1

    Mein Problem ist aber : Auß einem mir nicht ersichtlichen Grund rundet die Funktion auch bei x.5 ab, d.h. auch 3.5 wird zu 3 gerundet. Lustigerweise tut sie das aber nicht immer, sondern nur wenn x>2. D.h. 0.5 wird korrekt zu 1 gerundet, 1.5 wird korrekt zu 2 gerundet, aber alles >2, also z.b. 2.5,3.5,4.5 etc werden ab(also falsch) gerundet!

    Meine Frage nun : Warum ist das so, kann doch rein aus der logik her schonmal garnet sein weil ich ja auf "rest==0.5f" prüfe... Und warum verhält sich die Funktion für x<2 korrekt, für x>2 aber falsch??? Bin ich zu blöd oder ist das ein Compilerfehler???? 😉

    Alternativ könnt ihr mir natürlich auch eine einfache und gut funktionierende(vor allen dingen korrekt funktionierende) ANSI-C++ Funktion zum Runden von floats nennen 🙂

    THX
    Philipp



  • ich denke, du brauchst

    int round(float value) 
    { 
        return int(value+0.5);
    }
    


  • Liefer genau die gleichen Ergebnisse...

    Hier ein bild dazu aus dem testprogramm/Kommandozeile:

    http://www.codetown.de/stuff/error.jpg

    Philipp



  • Mhhh mir ist nochwas aufgefallen:

    Wenn ich die round-Funktion so teste, liefer er für den wert 3.5 die zahl 3 zurück, rundet also falsch!

    for(float i=3.0f;i<=4.1;i+=0.01f)
    {
    	cout<<"Zahl:\t"<<i<<"\tGerundete Zahl(round):\t"<<round(i)<<endl;
    }
    

    Wenn ich aber so teste, liefer er für 3.5 4 zurück, rundet also richtig:

    cout<<"Zahl:\t"<<3.5<<"\tGerundete Zahl(round):\t"<<round(3.5)<<endl;
    

    Warum macht der das?

    Philipp



  • Vielleicht wird es dir klarer, wenn du dir folgendes ausgeben lässt:

    for(double i=3.0f;i<=4.1;i+=0.01f) {
          cout<<"Zahl:\t"<<fixed<<setprecision(10)<<i<<"\tGerundete Zahl(round):\t"<<round(i)<<endl;
    }
    

    Als kleiner Ratschlag: Verwende nicht Gleitkommazahlen in for Schleifen.
    Die sind nämlich niemals ganz genau, und mit der Iteration wird der Wert immer ungenauer. Folgendes sollte zB korrekte Ergebnisse liefern:

    for (int i = 300; i < 410; ++i) {
      cout << "Zahl: " << i/100. << "; Gerundet: " << round(i/100.) << '\n';
    }
    


  • davie schrieb:

    Folgendes sollte zB korrekte Ergebnisse liefern:

    for (int i = 300; i < 410; ++i) {
      cout << "Zahl: " << i/100. << "; Gerundet: " << round(i/100.) << '\n';
    }
    

    leider nein.
    beispiel mit meinen vierstelligen dezimalzahlen:
    floor(1.000/3.0003.000)
    ==floor(0.3333
    3.000)
    ==floor(.9999)
    ==0.0000
    aber
    floor(2.000/3.0003.000)
    ==floor(0.6667
    3.000)
    ==floor(2.001)
    ==2.000
    bei diesen vierstelligen dualzahlen wirds im nachkommabreich ungenau, sobald man durch 3,6,7,9,11,12,13 oder sonst irgend ne zahl, die nicht produkt aus 2-en und 5-en ist, teilt.

    sobald man auf dem rechner mit seinem dualsystem als divisor keine zweierpotenz benutzt, wirds im nachkommabereich ungenau, und 100 ist leider keine zweierpotenz.



  • int round(float value)
    {
       return (int)value+0.5;
    }
    

    Es funktioniert, wenn der cast weggelassen wird, da sonst eine
    Integeraddition durchgefuehrt wird und keine Addition von
    float-Werten.

    mfg
    v R



  • virtuell Realisticer schrieb:

    int round(float value)
    {
       return (int)value+0.5;
    }
    

    Es funktioniert, wenn der cast weggelassen wird, da sonst eine
    Integeraddition durchgefuehrt wird und keine Addition von
    float-Werten.

    mfg
    v R

    deswegen schreibt man ja uch
    return int(value+0.5);
    oder
    return (int)(value+0.5);//hoch lebe der alte cast

    der cast ist nur da, die compilerwarnung wegzudrücken.



  • Ich glaube, ich muss mal meine Einstellungen bezueglich Warnungen etwas
    haeter einstellen, denn der BuilderX hat mir keine Warnung ausgegeben
    (was er ja eigentlich haette machen muessen, schliesslich geht ja die
    Genauigkeit floeten) 😉

    mfg
    v R


Anmelden zum Antworten