double variable nachkommastellen festlegen in C

Name1235

Banned
Registriert
Okt. 2015
Beiträge
51
Hallo,
wenn ich einer double Variable z.B. mit scanf einen Wert zuweise, so ist das ja nicht der exakt richtige Wert.
z.B. wenn ich eine 0,2 zuweise, könnte es auch 0,2000000001 oder 1,999999999999 heißen.

Wie kann ich das umgehen?
Ich brauche genau den Wert 0,2.
In printf kann ich ja dazu %.1lf schreiben.
Aber das geht ja bei scanf nicht, oder?
 
"Über eine Angabe wie "%3d" ließe sich beispielsweise die Eingabe eines ganzzahligen Wertes mit maximal drei Ziffern bestimmen."

Warum geht dann %.3lf nicht?
 
Ok, ich glaube ich habe das konkrete Problem gefunden.

Und zwar lese ich eine Kommazahl (zwei Nachkommastellen) zunächst als double ein.
Dann nehme ich die Zahl mal hundert und wandle sie in den typ int um.
Wenn die Zahl z.b. 0,19999999999 (anstelle der 0,20) ist, dann erhalte ich bei mal hundert
199,999999.
Wenn ich das in int umwandle ergibt sich 199 und nicht die benötigten 200.

Kann ich das irgendwie verhindern?

Falls ihr euch fragt, was ich damit bezwecken will:
Ich will einen Betrag in Euro einlesen (dazu brauche ich ja eine Kommazahl).
Dann will ich so lange von dem eingegebenen Betrag eine Zahl abziehen (z.B. 5 Cent), bis der Betrag Null wird.
Aber das geht meistens schief, da ja eine Gleitkommazahl nicht genau den eingegebenen Betrag annehmen kann.
Wenn also zB. der gespeicherte Betrag in der double variable 0,1999999 Euro ist, kann ich mit 0,05 Euro nie auf Null kommen :(
 
Bei Währungen würde ich generell immer in Cents rechnen, damit man genau diese Probleme nicht hat. Gib die Summen doch einfach ohne Komma also in Cent ein. (Statt 1,5€ dann 150C)
 
Du könntest auch einen String eingeben lassen und dann Euro und Cent - ints aus dem String extrahieren.
 
Wenn x der eingelesene Wert ist:
Code:
x += 0.000000000001;
x = int(x * 10) / 10.0;

Versuch mal so einzulesen:
Code:
double x;
std::cin >> x;

Wenn man dann 0.2 in der Konsole eingibt, bekommt man auch 0.2 für x ausgegeben.
 
S.Kara schrieb:
Versuch mal so einzulesen:
Code:
double x;
std::cin >> x;

Wenn man dann 0.2 in der Konsole eingibt, bekommt man auch 0.2 für x ausgegeben.

Warum sollte er denn für so ein leicht zu lösendes Problem gleich die Programmiersprache wechseln?
 
Du must passend runden. Einfaches Umwandeln in einen int rundet immer zum nächstniedrigen int ab.
So sollte es gehen zum nächsten ganzen cent-Wert zu runden:
double euro;
int cent
cent = (int) (euro *100 +0.5)

Und dann in cent weiterrechnen
 
Das geht doch ganz leicht zum rechnen. Warum macht ihr euch so einen Stress?
Code:
double x = 100.126;
x = (int)(x*100+0.5)/100.0; //x = 100.13
 
Wenn man dann 0.2 in der Konsole eingibt, bekommt man auch 0.2 für x ausgegeben.
Es ist aber immer noch nicht 0.2, sondern ein Wert, der nahe an 0.2 ist. Wenn man damit rechnet, fehlen dann auf einmal irgendwo ein paar tausend Euro.

Du könntest auch einen String eingeben lassen und dann Euro und Cent - ints aus dem String extrahieren.
Das ist die einzig sinnvolle Lösung, die ich hier in den Antworten bisher sehe - etwas aufwändiger zu implementieren, aber auf jeden Fall genau.
 
asdfman schrieb:
Warum sollte er denn für so ein leicht zu lösendes Problem gleich die Programmiersprache wechseln?
Ah sorry, habe mir irgendwie automatisch ein ++ dazu fantasiert. :D
Das was ich davor geschrieben habe sollte dann halt genau die Lösung sein, die hier gesucht wird.

VikingGe schrieb:
Es ist aber immer noch nicht 0.2, sondern ein Wert, der nahe an 0.2 ist. Wenn man damit rechnet, fehlen dann auf einmal irgendwo ein paar tausend Euro.
Das war C++ Code und doch, man bekommt dort exakt 0.2. In C dann halt so:
S.Kara schrieb:
Wenn x der eingelesene Wert ist:
Code:
x += 0.000000000001;
x = int(x * 10) / 10.0;
Danach hat man auch immer genau die 0.2.

Alternativ könnte man auch sagen man ließt die Werte ohne Komma als int ein und dividiert sie dann durch z.B. 10.
 
Zuletzt bearbeitet: (dividiert wird klein geschrieben :p)
Die round()-Funktion in Math.h für (kaufmännisch) korrektes Runden leistet dir an dieser Stelle womöglich gute Dienste. C rundet beim Datentypen-Casting ab.
 
Das war C++ Code und doch, man bekommt dort exakt 0.2.
Nur, weil du auf der Konsole dann vielleicht 0.2 stehen hast, ist das trotzdem nicht 0.2, einfach weil 0.2 mit double nicht darstellbar ist. Ob das nun C++ ist oder Brainfuck, spielt dabei keine Rolle - 0.2 als endliche Summe von Zweierpotenzen zu schreiben ist genau so unmöglich wie 1/3 als endliche Summe von Zehnerpotenzen zu schreiben (0.333333~). Und das fällt beim Rechnen quasi immer irgendwie ins Gewicht, besonders schwer bei Subtraktionen und Additionen (5000*0.2 ist was anderes als wenn man 5000x die Summe bildet).

Und das ist auch für Anfänger insofern relevant als dass diese gerne dazu neigen, Floating-Point-Zahlen mit == auf irgendwelche Werte zu überprüfen, was aber im Falle von Rechenergebnissen praktisch immer in die Hose geht. Und zwar genau aus dem Grund.
 
So lange man innerhalb von 17 Dezimalstellen bleibt, gilt 0.999...9 < 0.2 < 0.200...1.
Code:
	double w = 0.2000000000000001;
	double x = 0.2;
	double y = 0.1999999999999999;

	if (w == x) printf("w == x\n");
	if (w != x) printf("w != x\n");
	if (w < x) printf("w < x\n");
	if (w > x) printf("w > x\n");

	if (x == y) printf("x == y\n");
	if (x != y) printf("x != y\n");
	if (x < y) printf("x < y\n");
	if (x > y) printf("x > y\n");

	printf("------\n");

	y += 0.0000000000000001;
	if (x == y) printf("x == y\n");
	if (x < y) printf("x < y\n");
	if (x > y) printf("x > y\n");

	printf("------\n");

	y += 0.0000000000000001;
	if (x == y) printf("x == y\n");
	if (x < y) printf("x < y\n");
	if (x > y) printf("x > y\n");
Ausgabe:
w != x
w > x
x != y
x > y
------
x == y
------
x < y

Je nachdem was man mit den Zahlen sonst noch vor hat, muss man wegen der Ungenauigkeit aufpassen, da gebe ich dir Recht.

Bei Berechnungen mit Geld (was der TE ja anscheinend vor hat) würde ich aber sowieso zu int greifen. Das hat mehrere Vorteile.
 
Zurück
Oben