Problem beim rechnen mit float variablen


  • Mod

    Arcoth schrieb:

    Exaktheit bedeutet, dass das korrekte Ergebnis einer Operation, sofern es im zulässigen Wertebereich liegt, eindeutig in diesem Typen dargestellt werden kann.

    Demnach wären Fließkommazahlen exakt. Der Wertebereich ist doch nicht etwa Intervall der reellen/rationalen Zahlen, sondern die Menge der Zahlen die vom entsprechenden Fließkomma-Typ dargestellt werden können.

    Dann bring eine bessere Definition.



  • SeppJ schrieb:

    großbuchstaben schrieb:

    Nathan schrieb:

    Das ist der typische Fehler: float/double sind nicht für diskrete Größen (wie Geld) geeignet, sondern für Kontinuums.

    Floating point formate sind diskrete Größen und keineswegs für Kontinua geeignet. [...]
    Ein Vorteil von floating point ist, daß man einen größeren Zahlenbereich überstreichen (nicht überdecken) kann wegen des Exponenten, der nur logarithmisch viele Bits braucht.

    Vollkommener Blödsinn.

    LOL 👍

    SeppJ schrieb:

    Wenn du wirklich glaubst, dass [...]

    tldnr;

    SeppJ schrieb:

    What every computer scientist should know about floating-point arithmetic

    eines meiner Lieblingspaper - viel Spaß beim Schmökern



  • Hallo, danke für die vielen Antworten, ich habe nun versucht das ganze in integer umzuwandeln und in Cent zu rechnen, allerdings klappt auch das bei einigen Werten nicht, weil der eingelesene Wert mit scanf("%f",&betrag) schon falsch ist:

    wenn ich zum Beispiel 4.68 eingebe, bekommt die Variable betrag den Wert 4.679999999

    also müsste ich wohl darauf verzichten, float als einlese Datentyp zu verwenden, wie kann man ansonsten aber eine kommazahl einlesen? (Wir müssen es mit scanf machen, cin cout ist nicht erlaubt ....)

    Danke im Voraus!



  • eventuell gibts ja ausser %f noch etwas, was besser passt:

    http://www.cplusplus.com/reference/cstdio/scanf/



  • Pures Fett schrieb:

    [...] allerdings klappt auch das bei einigen Werten nicht, weil der eingelesene Wert mit scanf("%f",&betrag) schon falsch ist: [...]

    #include <iostream>
    
    int main()
    {
    	unsigned  euro;
    	unsigned  cent;
    	char      delim;
    
    	while( !( std::cin >> euro >> delim >> cent ) ||
    	       !( delim == '.' || delim == ',' ) ||
    		   euro > 5 ||
    		   ( euro == 5 && cent ) || 
    		   cent > 99 )
    
    	{
    		std::cerr << "Input error! Please try again!\n\n";
    	}
    
    	unsigned amount{ euro * 100 + cent };
    
    	std::cout << "in cents: " << amount;
    }
    

    ...

    ~// scheisz tags!!~



  • __someone schrieb:

    eventuell gibts ja ausser %f noch etwas, was besser passt:

    http://www.cplusplus.com/reference/cstdio/scanf/

    hmm also die Tabelle habe ich auch schon gesehen aber so wie ich das verstehe kann man nur mit %f %e %g (welche ja gleich zu seien scheinen) eine dezimalzahl MIT komma einlesen, habe auch versucht ob man scanf("%.2f",&betrag") machen kann, damit er sich dann nicht verrechnet bei nur 2 Stellen aber das funktioniert nicht.

    Also eine andere Möglichkeit wäre, den eingelesenen float Wert gleich in vor und nachkomma aufzuteilen, aber der Befehel dazu ist mir nicht geläufig (ich habe was von ceil(variable)) gelesen, aber auch das würde nicht funktionieren, wenn er direkt den Wert der Variable falsch einließt, wie ich schrieb aus 4.68 wird 4.67999999 😕

    @swordfish:

    ich glaube dein programm gibt nur cent und euro aus aber nicht die einzelnen Münzen also in der aufteilung wieviel 2euro münzen, 1 euro münzen etc das ist jedoch meine Aufgabenstellung. Leider dürfen wir wie geschrieben auch kein cin cout machen sondern müssten printf und scanf verwenden >_>

    Vielleicht müsste man gleich vor und nachkomma trennen in seperate Variablen einlesen, dann auf 2 stellen aufrunden und dann wieder beide zusammenrechnen als Cent betrag. Hätte jemand einen Vorschlag wie ich das machen könnte?

    int vorkomma= ceil(betrag); < müsste dann hier nur noch aufrunden
    int nachkomma= betrag- vorkomma; < und hier

    hilfsvariable=vorkomma+nachkomma;



  • Pures Fett schrieb:

    Hallo, danke für die vielen Antworten, ich habe nun versucht das ganze in integer umzuwandeln und in Cent zu rechnen, allerdings klappt auch das bei einigen Werten nicht, weil der eingelesene Wert mit scanf("%f",&betrag) schon falsch ist:

    wenn ich zum Beispiel 4.68 eingebe, bekommt die Variable betrag den Wert 4.679999999

    also müsste ich wohl darauf verzichten, float als einlese Datentyp zu verwenden, wie kann man ansonsten aber eine kommazahl einlesen? (Wir müssen es mit scanf machen, cin cout ist nicht erlaubt ....)

    Danke im Voraus!

    Das Problem ist, dass die Dezimalzahl 4.68 als float nicht exakt darstellbar ist. Der Computer hilft sich damit, dass er die nächst mögliche Fliesskommazahl speichert. Und dabei kommt es eben zu einen kleinen Fehler. Wenn Du die Zahl wieder ausgeben möchtest, dann versucht der Computer wieder sein bestes und konvertiert die Binärzahl wieder in Dezimal und macht damit den Fehler sichtbar.

    Die Lösung ist, entweder ganz auf Fliesskommazahlen zu verzichten, und zwar schon bei der Eingabe, oder mit dem Rundungsfehler leben und bei der Ausgabe die Zahl runden. Wenn Du den Wert 4.679999999 mit 2 Nachkommastellen ausgibst, dann zeigt der Computer 4.68. Und siehe da: das ist genau das, was Du eingegeben hast.

    Das steht sicher ausführlicher und exakter in dem genannten Paper. Ich habe mir das nicht angeschaut.



  • tntnet schrieb:

    Das Problem ist, dass die Dezimalzahl 4.68 als float nicht exakt darstellbar ist. Der Computer hilft sich damit, dass er die nächst mögliche Fliesskommazahl speichert. Und dabei kommt es eben zu einen kleinen Fehler. Wenn Du die Zahl wieder ausgeben möchtest, dann versucht der Computer wieder sein bestes und konvertiert die Binärzahl wieder in Dezimal und macht damit den Fehler sichtbar.

    Die Lösung ist, entweder ganz auf Fliesskommazahlen zu verzichten, und zwar schon bei der Eingabe, oder mit dem Rundungsfehler leben und bei der Ausgabe die Zahl runden. Wenn Du den Wert 4.679999999 mit 2 Nachkommastellen ausgibst, dann zeigt der Computer 4.68. Und siehe da: das ist genau das, was Du eingegeben hast.

    Das steht sicher ausführlicher und exakter in dem genannten Paper. Ich habe mir das nicht angeschaut.

    Danke das verstehe ich, jedoch kann man dann einen Vergleich einer float variable nicht wirklich machen da es hierbei zu fehlern kommt. Aber es gibt ja ettliche programme, bei denen man kommabeträge eingibt und die mit diesen dann rechnen und vergleichen. Die Frage ist nur, wie man das Problem umgehen kann.



  • Pures Fett schrieb:

    @swordfish:

    ich glaube dein programm gibt nur cent und euro aus aber nicht die einzelnen Münzen also in der aufteilung wieviel 2euro münzen, 1 euro münzen etc das ist jedoch meine Aufgabenstellung. Leider dürfen wir wie geschrieben auch kein cin cout machen sondern müssten printf und scanf verwenden >_>

    Du hast nach dem Einlesen gefragt ... und ein bißchen Eigeninitiative darf man doch wohl erwarten? Na, egal.

    #include <cstddef>
    #include <cstdio>
    
    int main()
    {
    	unsigned const coins[]{ 200, 100, 50, 20, 10, 5, 2, 1 };
    
    	unsigned  euro;
    	unsigned  cent;
    	char      delim;
    
    	while( std::scanf( "%u%c%u", &euro, &delim, &cent ) != 3 ||
    	       !( delim == '.' || delim == ',' ) ||
    		   euro > 5 ||
    		   ( euro == 5 && cent ) || 
    		   cent > 99 )
    
    	{
    		std::fputs( "Input error! Please try again!\n\n", stderr );
    	}
    
    	unsigned amount{ euro * 100 + cent };
    
    	std::printf( "Amount in cents: %u\n\n", amount );
    
    	while( amount )
    	{
    		for( std::size_t i{}; i < sizeof coins / sizeof *coins; ++i ) {
    			if( amount / coins[ i ] ) {
    				std::printf( "%1.2f\n", coins[ i ] / 100. );
    				amount -= coins[ i ];
    				--i;
    			}
    		}
    	}
    }
    


  • Was passiert bei der Eingabe von 4.9 oder 4.90 ?

    Reicht die Eingabe als float nicht aus und dann

    int cent_betrag = (betrag + 0.005) * 100
    

    ?

    Pures Fett schrieb:

    Aber es gibt ja ettliche programme, bei denen man kommabeträge eingibt und die mit diesen dann rechnen und vergleichen.

    Rechnen kannst du ja damit.
    Der Vergleich auf Gleichheit ist problematisch.

    Du müßtest z.B. noch überprüfen, ob nur zwei Nachkommstaellen (und nicht mehr) eingegeben wurde.
    Da du noch Anfänger bist, lässt du die Lösung für das Problem erstmal sein und lernst den Rest der Sprache.



  • DirkB schrieb:

    Was passiert bei der Eingabe von 4.9 oder 4.90 ?

    Reicht die Eingabe als float nicht aus und dann

    int cent_betrag = (betrag + 0.005) * 100
    

    ?

    unsigned amount{ euro * 100 + ( cent < 10 ? cent * 10 : cent ) };
    

    :p


Anmelden zum Antworten