Geldbetrag Ausgabe in Eur/Cent < Softwaretechnik+Pro < Praktische Inform. < Hochschule < Informatik < Vorhilfe
|
Status: |
(Frage) beantwortet | Datum: | 22:32 So 30.10.2011 | Autor: | steftn |
Aufgabe | #include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
float Eingabe;
int euro,cent;
printf("Gib den Geldbetrag [mm] ein:\n");
[/mm]
scanf("%f", &Eingabe);
euro=(int)Eingabe;
Eingabe=Eingabe*100;
cent=(Eingabe)-(euro*100);
[mm] printf("\n\nDer [/mm] Betrag ist %d Euro und %d [mm] Cent\n\n", [/mm] euro, cent);
system("PAUSE");
return 0;
} |
Hallo,
obiges Programm soll den Geldbetrag in Euro und Cent ausgeben.
Wenn man z.b. 568.98 Euro eingibt, kommt folgendes raus:
" Der Betrag ist 568 Euro und 98 Cent"
ok, das funktioniert soweit.
Als ich aber mehrere Beträge durchprobiert habe, klappte es bei diesen Betrag nicht:
147.15
Das Programm gibt dann " 147 Euro und 14 Cent" aus!!!!!!!!
Wiso stimmen die Cent nicht?????
Ich kann mir das nicht erklären, weiß das jemand wiso das nicht stimmt?
Ich wär für jeden Tipp dankbar
|
|
|
|
moin steftn,
Beim Casten von Float zu Int gehen einige Infos verloren.
Es könnte sein, dass dies hier das Problem ist.
Versuche mal in der Berechnung des Centbetrags nicht euro selbst zu benutzen sondern die ursprüngliche Eingabe, also den Float und caste erst, nachdem berechnet wurde.
Vielleicht klappt es dann. ;)
lg
Schadow
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 00:33 Mo 31.10.2011 | Autor: | steftn |
Hallo,
danke für deine Antwort, aber leider komm ich nicht auf die Lösung.
Der "Cent-Wert", also quasi der Nachkommawert soll zu integer umgewandelt werden.
Folgendes hab ich gefunden:
http://msdn.microsoft.com/de-de/library/bb978923.aspx
"Rundungsfehler beim Umwandeln von Fließkommawerten in Ganzzahlwerte"
Anscheinend handelt es sich um ein größeres Problem.
mhm, hätt vielleicht jemand eine Lösung des Problems?
|
|
|
|
|
Hallo steftn,
> danke für deine Antwort, aber leider komm ich nicht auf
> die Lösung.
>
> Der "Cent-Wert", also quasi der Nachkommawert soll zu
> integer umgewandelt werden.
>
> Folgendes hab ich gefunden:
> http://msdn.microsoft.com/de-de/library/bb978923.aspx
> "Rundungsfehler beim Umwandeln von Fließkommawerten in
> Ganzzahlwerte"
>
> Anscheinend handelt es sich um ein größeres Problem.
>
> mhm, hätt vielleicht jemand eine Lösung des Problems?
Na, so tief in die Programmarchitektur willst Du doch bei so einer einfachen Fragestellung gar nicht einsteigen.
Um solche Fehler zu umgehen, ist es gut zu wissen, ob die Abweichung immer in der gleichen Richtung geschieht oder z.B. bei positiven und negativen Zahlen in jeweils entgegengesetzter Richtung auftritt.
Meist genügt es aber völlig, zur Vermeidung des Fehlers ein Korrekturglied einzufügen und durch Rundung (bzw. Abschneiden des Vor- oder Nachkommaanteils) wieder abzuschneiden.
Wenn f also die Fließkommazahl ist, e die Integerzahl "Euro" und c die Integerzahl "Cent" ist, kann wird das Korrekturglied k als Fließkommazahl so eingefügt:
e=int(f+k)
c=int(100*(f-e+k)) oder (je nach Fehlergröße) c=int(100*(f-e)+k)
Dabei sollte k wahrscheinlich in der Größenordnung [mm] 0.0025\le k\le{0.0075} [/mm] gewählt werden.
Beinhaltet der Befehl "int" (Ganzzahl) eine Rundungsroutine, dann sollte wahrscheinlich [mm]k<0.0025[/mm] gewählt werden.
Das ist die einfachste Lösung. Probiers mal aus.
Grüße
reverend
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 02:52 Mo 31.10.2011 | Autor: | steftn |
tadaaaaa, es funzt!!!! Super, vielen vielen dank
Ich versteh zwar immer noch nicht ganz, wiso C da einen "Rundungsfehler?" macht, aber naja...
Hier mein neues funktionierendes Programm:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
float betrag,korr;
int euro, cent;
printf("Geben Sie einen Betrag ein: ");
scanf("%f", &betrag);
korr = 0.005;
euro=(int)(betrag+korr);
cent=(int)(100*(betrag-euro+korr));
[mm] printf("\n\nDer [/mm] Betrag [mm] von\n%d [/mm] Euro und %d [mm] Cent\nkann aus\n\n", [/mm] euro, cent);
system("PAUSE");
return 0;
}
....By the way: weiß jemand, wie man das ausschalten kann, dass hier dieses Forum nicht andauernd die C-Codes umwandelt??? Kann man den Mathematischen Textsatz hier irgendwie abstellen?
Kann man das abstellen: https://vorhilfe.de/mm
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 03:51 Mo 31.10.2011 | Autor: | reverend |
Hallo nochmal,
> tadaaaaa, es funzt!!!! Super, vielen vielen dank
Schön, das ist erstmal die Hauptsache. Versuche, k so klein wie möglich und so groß wie nötig zu wählen. Probier dazu auch negative Betragseingaben.
> Ich versteh zwar immer noch nicht ganz, wiso C da einen
> "Rundungsfehler?" macht, aber naja...
Die Erklärung, die Du selbst verlinkt hattest, ist dazu doch gar nicht schlecht.
> ....By the way: weiß jemand, wie man das ausschalten kann,
> dass hier dieses Forum nicht andauernd die C-Codes
> umwandelt??? Kann man den Mathematischen Textsatz hier
> irgendwie abstellen?
Man kann, aber es ist mühsam. Das Problem ist, dass man dazu wissen muss, was der Parser als LaTeX-interpretierbar erkennt. Diese Information ist aber nirgends dokumentiert, ich selbst weiß auch nur aufgrund einiger Eingabeerfahrung hier so ein paar Fallen.
Jedenfalls kannst Du die Formel-Interpretation vermeiden, indem Du die sonst automatisch interpretierten Stellen in eine Befehlsklammer einschließt (s.u.).
Die entsprechende Klammer für die LaTeX-Interpretation ist ja, wie dokumentiert, folgende: [mm]zu interpretierende Eingabe[/mm].
Der Parser erkennt nun automatisch (aber eben manchmal fehlerhaft), was im Formelsatz darzustellen ist, und fügt die Befehlsklammer ein.
Um das zu vermeiden, muss der Text, der automatisch erkannt wird, wie folgt geklammert werden: [ code ] Ausnahme [ /code ].
hmm. Schwer zu überlisten.
Natürlich gehören da keine Leerzeichen um die Anweisung code bzw. /code herum, sondern direkt die eckigen Klammern.
> Kann man das abstellen: https://vorhilfe.de/mm
Tja, mal sehen, ob ich das hier überhaupt richtig eingegeben habe. Wenn nicht, wird es vielleicht noch ein paar Revisionen dauern...
So, soweit erst einmal die Textdarstellung.
Mit anderen Worten: häng lieber eine Text(-editor-)datei an, oder binde eine Grafik ein. In beiden Fällen fällt es ein bisschen schwer, direkt zu kommentieren oder korrigieren, aber wir kriegen das dann schon hin...
Grüße
reverend
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 04:26 Di 01.11.2011 | Autor: | steftn |
Hallo,
nochmal bezüglich meines Programmes:
wenn ich als Korrekturfaktor 0.005 verwende, habe ich leider Probleme, wenn ich mit den Gelbeträgen in die 100.000-Marke komme... dann gibt es nämlich ab da wieder einen Rundungsfehler!
Dementsprechend muss ich dann den Korrekturwert anpassen, dann passt es wieder... das gleiche ist bei überschreitung der Million-Marke.
mhm, meine Lösung passt eigentlich schon, aber irgendwie bin ich selbst nicht damit zufrieden, dass ich ggf. den Korrekturwert anpassen muss.... mhm
Also eine 100%ige passende Lösung scheint es dann nicht zu geben? Vielleicht irgendein Befehl oder kleines Programm?
|
|
|
|
|
> Hallo,
>
> nochmal bezüglich meines Programmes:
>
> wenn ich als Korrekturfaktor 0.005 verwende, habe ich
> leider Probleme, wenn ich mit den Gelbeträgen in die
> 100.000-Marke komme... dann gibt es nämlich ab da wieder
> einen Rundungsfehler!
>
> Dementsprechend muss ich dann den Korrekturwert anpassen,
> dann passt es wieder... das gleiche ist bei überschreitung
> der Million-Marke.
>
> mhm, meine Lösung passt eigentlich schon, aber irgendwie
> bin ich selbst nicht damit zufrieden, dass ich ggf. den
> Korrekturwert anpassen muss.... mhm
... wirklich lästig
> Also eine 100%ige passende Lösung scheint es dann nicht zu
> geben? Vielleicht irgendein Befehl oder kleines Programm?
Hallo steftn,
über die z.T. etwas haarsträubenden Rundungsprobleme
in C++ habe ich mich schon auch gewundert. Im Netz
findet man dazu ganze Abhandlungen.
Für dein Problem sähe ich folgende Lösung:
x: Betrag (float-Zahl) (x>=0 vorausgesetzt)
e,c: Euros, Cents (int-Zahlen)
cc: Gesamtbetrag in Cents (int-Zahl)
1.) berechne cc = floor(100*x+0.5)
2.) berechne e = floor(cc/100)
3.) berechne c = cc-100*e
Ich wäre erstaunt, wenn das auch noch zu Macken
führen würde ...
LG Al-Chw.
|
|
|
|
|
Status: |
(Frage) beantwortet | Datum: | 14:01 Di 01.11.2011 | Autor: | steftn |
Hallo,
@Al-Chwarizmi:
danke für deine Idee, aber leider funktioniert es bereits schon mit einigen 100.000-Werten nicht mehr richtig, da gibts wieder Rundungsfehler :-(
Hier das ausgetestete Programm nach deiner Idee:
Klick mich
|
|
|
|
|
Hallo steftn,
dann ändere mal noch zwei Zeilen:
e=floor(cc/100+0.5)
c=floor(cc-100*e+0.5)
Das ist jetzt echt brute force, aber wenn das nicht funktioniert, dann weiß ich schlicht nicht mehr weiter, ohne tatsächlich in die Variablenroutinen des Compilers einzutauchen. Falls ich die überhaupt verstehe, was eher unwahrscheinlich ist.
Grüße
reverend
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 18:12 Di 01.11.2011 | Autor: | steftn |
Hallo,
@reverend:
danke für deine Idee. Hier das umgesetzte Programm:
Klick mich
Habs probiert. Manche 100.000-Werte gehen, manche nicht.
Der Wert hier geht z.b. nicht:
549786.14
Das Programm gibt dann folgendes aus:
Euro: 549786 Cent:13
Also gehts leider wieder nicht, schade :-(
gruß
|
|
|
|
|
Hallo!
Das Problem ist die Darstellung einer Fließkommazahl im Binärformat des Computers.
Ein INT beispielsweise kann aus 4 Byte bestehen, und kann damit jede ganze Zahl von -4'294'967'296 bis 4'294'967'295 darstellen. Man kann also sagen, daß das INT bis zu 10 Ziffern darstellen kann. ( wohl gemerkt, "bis zu". Die Zahl 8'000'000'000 geht NICHT)
Ein FLOAT besteht auch gerne aus 4 Byte, allerdings werden von diesen 32 Bit einige für den Exponenten benutzt, sodaß nicht mehr so viele für die eigentlichen Stellen übrig bleiben.
Die Präzision, d.h. die Anzahl der Stellen ist daher nicht sonderlich groß für ein FLOAT, dafür weiß es eben, ob es um "5 tausend", "5 Millonen", oder "5 hundert trillionen" geht.
Du kannst statt FLOAT ein DOUBLE benutzen, das hat meist 8 byte, und damit mehr Präzision. Allerdings auch nicht viel, die zusätzlichen Bits werden in erster Line dafür verwendet, noch größere Exponenten zu speichern. Das FLOAT kann maximal sowas wie [mm] 1^{38} [/mm] darstellen, das DOUBLE bis zu [mm] 10^{308} [/mm] . Aber ein paar mehr Bits gibt es schon für die Ziffern ansich.
Hier ein kleines Programm:
1: |
| 2: | #include <iostream>
| 3: | #include <limits.h>
| 4: | #include <iomanip>
| 5: | using namespace std;
| 6: |
| 7: | int main() {
| 8: |
| 9: | float f=549786.145678901234;
| 10: | double d=549786.145678901234;
| 11: |
| 12: | cout << "float: "<< setprecision(20)<< f <<endl;
| 13: | cout << "double: "<< setprecision(20)<< d <<endl;
| 14: |
| 15: | return 0;
| 16: | }
|
Das Programm definiert zwei Zahlen f und d als FLOAT und DOUBLE, und weist ihnen deine problematische Zahl zu. Ich habe noch ein paar Ziffern hinten dran gestellt, um das Problem zu verdeutlichen. Die Ausgabe des Programms sieht so aus:
float: 549786.125
double: 549786.14567890122999
Du siehst: Beim FLOAT stimmt schon die zweite Nachkommastelle nicht, das ergibt in deinem Programm sowas wie 12 oder 13Ct.
Das DOUBLE hält länger durch, hier stimmen noch 10 Nachkommastellen.
Warum genau das passiert, was hier passiert, ist etwas langatmig, aber du solltest wissen, daß die Anzahl an Stellen, die in einem float gespeichert werden können, nicht sonderlich groß ist.
Du solltest nun einfach ein DOUBLE verwenden, und dich damit abfinden, daß das Programm für die Staatsverschuldung so manchen Landes in nächter Zeit nicht richtig funktioniert. Aber auf die paar Ct. kommts dann auch nicht mehr an.
|
|
|
|
|
Hallo!
Eine Sache seh ich noch:
Weil sich Kommazahlen schlecht von unserem Zehnersystem ins Binärsystem übertragen lassen, kommt es häufiger zu Rundungsfehlern.
Du gibst 1.15 als Zahl an, der Computer speichert das aber als 1,14999999999
Da du deine Cent als INT definiert hast, wird einfach die Nachkommastelle abgeschnitten, und dann bekommst du 14Ct raus.
Definier die cent auch mal als double, und formatier die im printf auch mit %lf. Dann solltest du diesen Effekt sehen können.
|
|
|
|
|
Status: |
(Mitteilung) Reaktion unnötig | Datum: | 13:02 Mi 02.11.2011 | Autor: | chrisno |
Da Du immer ganze ct haben wirst und haben willst, würde ich einen String einlesen. Dann kannst Du in Ruhe analysieren, ob überhaupt eine gültige Eingabe erfolgt ist: Ziffern evnetuell Komma danach bis zu zwei Ziffern. Den String zerlegst Du in zwei Integer und dann kann nichts böses mehr passieren.
Das habe ich mir für alle Eingaben angewöhnt, die von Anwendern kommen. Aber auch beim Einlesen aus Dateien ist das durchaus nützlich.
|
|
|
|
|
> zumindest hab ich jetzt gelernt, das
> man in C auf solche Sachen aufpassen muss.
>
> Es kann also quasi keine 100%ige Lösung geben
Es ist doch sehr beruhigend zu wissen, dass wegen
ähnlicher Softwareprobleme schon Raketen mit kostbarer
Nutzlast statt im All im Ozean angekommen sind.
Daneben wirken deine Probleme, bei denen es um plus
oder minus einen Cent geht, doch ziemlich bescheiden ...
(Vorsicht: das war absolut zynisch gemeint )
Al
|
|
|
|