Forum: PC-Programmierung C - Fehler bei Berechnung


von Daniel S. (dani2304)


Lesenswert?

Hallo,
ich bin ein Neuling beim Programmieren und hätte eine Frage an euch.
Bei meinem Programm:
1
int Geld(){
2
   short Auswahl, Zwei=0, Eins=0, FZ=0, ZW=0, ZN=0, F=0, Z=0, E=0;
3
    double Wasser=1.38, Cola=1.76, Fanta=2.89, GeldE=0, Rueck=0
4
5
    printf("Welches Getraenk wuenschen Sie?\n\nDruecken Sie die:\n1    Wasser 1,38 Euro\n2    Cola 1,76 Euro\n3    Fanta 2,89 Euro\n\n");
6
    scanf("%hd",&Auswahl);
7
8
    while(Auswahl<1 || Auswahl>3){
9
    printf("Diese Nummer unterstuetz kein Produkt. Geben sie erneut die Zahl fuer ihr gewuenschtes Produkt ein: \nDruecken Sie die:\n1    Wasser 1,38 Euro\n2    Cola 1,76 Euro\n3    Fanta 2,89 Euro\n\n");
10
    scanf("%hd",&Auswahl);
11
    }
12
13
    printf("Geldeingabe >10Euro:");
14
    scanf("%lf",&GeldE);
15
16
    if(GeldE<10){
17
    printf("\nDer eingegebene Geldbetrag ist zu gering!");
18
    return -1;
19
    }
20
21
    if(Auswahl==1){
22
    Rueck=GeldE-Wasser;
23
    printf("\nIhr Wasser wird nun ausgegeben. Das Rueckgabegeld betraegt:  %.2lf Euro\n", Rueck);
24
    }
25
26
    if(Auswahl==2){
27
    Rueck=GeldE-Cola;
28
    printf("\nIhre Cola wird nun ausgegeben. Das Rueckgabegeld betraegt:  %.2lf Euro\n", Rueck);
29
    }
30
31
    if(Auswahl==3){
32
    Rueck=GeldE-Fanta;
33
    printf("\nIhre Fanta wird nun ausgegeben. Das Rueckgabegeld betraegt:  %.2lf Euro\n", Rueck);
34
    }
35
36
    while(Rueck>=2){
37
    Zwei+=1;
38
    Rueck-=2;
39
    }
40
41
    while(Rueck>=1){
42
    Eins+=1;
43
    Rueck-=1;
44
    }
45
46
    while(Rueck>=0.5){
47
    FZ+=1;
48
    Rueck-=0.5;
49
    }
50
51
    while(Rueck>=0.2){
52
    ZW+=1;
53
    Rueck-=0.2;
54
    }
55
56
    while(Rueck>=0.1){
57
    ZN+=1;
58
    Rueck-=0.1;
59
    }
60
61
    while(Rueck>=0.05){
62
    F+=1;
63
    Rueck-=0.05;
64
    }
65
66
    while(Rueck>=0.02){
67
    Z+=1;
68
    Rueck-=0.02;
69
    }
70
71
    while(Rueck!=0.0){
72
    E+=1;
73
    Rueck-=0.01;
74
    }
75
76
    printf("Ausgabe Zwei Euro Muenzen:%i \n",Zwei);
77
    printf("Ausgabe Ein Euro Muenzen:%i \n",Eins);
78
    printf("Ausgabe Fuenfzig Cent Muenzen:%i \n",FZ);
79
    printf("Ausgabe Zwanzig Cent Muenzen:%i \n",ZW);
80
    printf("Ausgabe Zehn Cent Muenzen:%i \n",ZN);
81
    printf("Ausgabe Fuenf Cent Muenzen:%i \n",F);
82
    printf("Ausgabe Zwei Cent Muenzen:%i \n",Z);
83
    printf("Ausgabe Ein Cent Muenzen:%i \n",E);
84
85
    return 0;
86
    }

Bei manchen Kombinationen wie z.B. wähle ich zuerst "1" an für 'Wasser'. 
Und gebe den Geldbetrag "39" ein. Dann zählt das Programm für 'Z' nicht 
hoch. Obwohl "Rueck>=0.02" sein sollte...

Könntet ihr mir da helfen?

von Jim M. (turboj)


Lesenswert?

Man schreibe das ganze auf Eurocents um und verwende nur ganze Zahlen.

Die Floats haben gar lustige Abweichungen wenn man große zu kleinen 
Zahlen addiert und subtrahiert.

von g457 (Gast)


Lesenswert?

> Obwohl "Rueck>=0.02" sein sollte...

Sollte, aber nicht ist. Wenn Du exakt rechnen willst, dann musst Du 
entweder andauern auf 0.01 Geldeinheiten runden oder (einfacher) Dich 
mit Festkommaarithmetik anfeinden.

HTH

von Daniel S. (dani2304)


Lesenswert?

Okay Vielen Dank das wusste ich nicht!

von Sebastian S. (amateur)


Lesenswert?

Runden ist meist keine runde Sache!

Gerade bei Werten, die mit Geld zu tun haben, ist die Ganzzahlarithmetik 
das Beste, was Du Dir antun kannst.

Bei modernen Rechnern hat ein Integer 64 Bit. Das sollte sogar für 
Automaten, die Kleinstaaten verkaufen, reichen. Haben diese keinen 
"natürlichen" Groß-Integer, so stellen die üblichen Bibliotheken auch 
den Wert: longint oder (u)int64_t zur Verfügung.

Intern sieht das ganze recht einfach aus: Ein Euro sind 100 Cent. Da 
gibt es nichts zu Runden und zu verstecken.

Bei der Ausgabe brauchst Du nur die einfache Division durch 100, setzt 
Dein Komma, und gibst die restlichen Cent aus.

Übrigens: Die gesetzlichen Vorschriften zum "wahren" Runden füllen 
viele, viele Seiten Gesetzestext.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Wenn du wissen willst, weshalb das so ist, dann versuch mal, 0,1 als 
Summe von Binärbrüchen darzustellen. Also
    0,1 = (a * 1/2) + (b * 1/4) + (c * 1/8) + ...
mit a,b,c,... entweder 0 oder 1. Du wirst merken, dass das nie endet, 
dass also 0,1 in endlicher Stellenzahl so überhaupt nicht exakt 
darstellbar ist.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Wenn du wissen willst, weshalb das so ist, dann versuch mal, 0,1 als
> Summe von Binärbrüchen darzustellen. Also
>     0,1 = (a * 1/2) + (b * 1/4) + (c * 1/8) + ...
> mit a,b,c,... entweder 0 oder 1. Du wirst merken, dass das nie endet,
> dass also 0,1 in endlicher Stellenzahl so überhaupt nicht exakt
> darstellbar ist.

Oder anders gesagt: So wie im Dezimalsystem 1/3 eine periodische Zahl 
ist, ist im Dualsystem auch 1/5 (und damit auch 1/10) eine solche. Somit 
kann in einer entsprechenden Gleitkommazahl unabhängig von ihrer 
Genauigkeit der Wert 0,1 nicht gespeichert werden - es entsteht eine 
kleine Abweichung.

von Purzel H. (hacky)


Lesenswert?

So ein Problem kann man auch Single-Steppen...

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Bleib doch einfach bei einer Schreibweise, dann klappts auch mit 
Rundungsfehlern:
1
    while(Rueck>=0.01){
2
    E+=1;
3
    Rueck-=0.01;
4
    }

: Bearbeitet durch User
von Achim (Gast)


Lesenswert?

Tim T. schrieb:
> Bleib doch einfach bei einer Schreibweise, dann klappts auch mit
> Rundungsfehlern:
>   while(Rueck>=0.01){
>     E+=1;
>     Rueck-=0.01;
>     }

Wobei in allen Fällen die Vergleichszahl ein wenig kleiner sein muss! 
Hier z.b >=0.009.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Daniel S. schrieb:
> printf("Geldeingabe >10Euro:");
> scanf("%lf",&GeldE);
>
> if(GeldE<10){
> printf("\nDer eingegebene Geldbetrag ist zu gering!");
> return -1;
> }

"fachliche" Kritik (Leute, es ist Freitag!)

exakt 10 EUR ist also nicht eingebbar (<10 wird nicht akzeptiert, und 
Betrag muß >10 sein). Also müßte ich 20 EUR eingeben. Und bekomme dann 
20,00 -1,38 = 18,62 EUR Wechselgeld raus, womöglich in Münzen.

Vermutlich ist der Automat ne Klimperkiste, mit dem Bauch voller 
Wechselgeld. Und die Kunden müssen immer große Scheine mithaben, um 
überhaupt ein Getränk ziehen zu können.

Und 1,38 als Betrag? Marketingtechnisch eh ein Preis, der eher 
ungeschickt ist (noch schlechtere Akzeptanz hätte vielleich 1,34 oder 
1,37 ans krummer Wert).

Ausserdem: 1,38 für ein Wasser, vermutlich sogar nur 0,33 Liter. Macht 
4,14 EUR pro Liter! Dafür bekommt man ja schon ne Flasche Wein. Naja, 
vielleicht sinds Flughafen-Preise.

Schönes Wochenende!

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.