Probleme mit kopfgesteuerter while-Schleife (Rundungsfehler)
-
Ich erlaube mir diesen geschlossenen Thread noch einmal kritisch zu betrachten.
Ich sehe in anderen Threads immer wieder die Diskussion, ob ein Befehl noch nach den Regeln des letzten Jahrtausend (C99) konform oder nicht konform ist. Da werden nur Kommata und Klammern korrigiert, aber wesentliche algorithmische Probleme und DV-Probleme bleiben oft außen vor.
Kommen wir zun Wechselgeld-Programm zurück. Ich habe versucht, alle Anweisungen (bis auf fscanf_s) auf den Stand von C99 zurückzuführen. Mögliche Unterlassungssünden bitte ich zu entschuldigen.
Was ich diskutieren und zeigen will, dass der fehlende Festkommadatentyp in C<2000 für kaufmännische Probleme nicht prädestiniert, was der Geldwechsler deutlich zeigt:
/*A031W_Wechselgeld.c : Einstiegspunkt der Konsolenanwendung*/ /*Festkommazahl-Manipulation am Beispiel eines Geldwechslers*/ #include <stdio.h> #include <stdlib.h> /*fuer system*/ void naiv(double nBetrag) { int nAnzahl2,nAnzahl1,nAnzahl05,nAnzahl02,nAnzahl01,nAnzahl005,nAnzahl002,nAnzahl001; nAnzahl2=nAnzahl1=nAnzahl05=nAnzahl02=nAnzahl01=nAnzahl005=nAnzahl002=nAnzahl001=0; while (nBetrag>=2) { nAnzahl2++; nBetrag-=2; } /*while*/ if (nBetrag>=1) { nAnzahl1=1; nBetrag-=1; } /*if*/ if (nBetrag>=0.5) { nAnzahl05=1; nBetrag-=0.5; } /*if*/ while (nBetrag>=0.2) { nAnzahl02++; nBetrag-=0.2; } /*while*/ if (nBetrag>=0.1) { nAnzahl01=1; nBetrag-=0.1; } /*if*/ if (nBetrag>=0.05) { nAnzahl005=1; nBetrag-=0.05; } /*if*/ while (nBetrag>=0.02) { nAnzahl002++; nBetrag-=0.02; } /*while*/ if (nBetrag>=0.01) { nAnzahl001=1; nBetrag-=0.01; } /*if*/ if (nBetrag!=0) printf("Hier muss ein Rundungsfehler vorliegen: %le\n",nBetrag); printf("Werte Euro/Cent: 2,00 1,00 0,50 0,20 0,10 0,05 0,02 0,01\n"); printf("Stueckelung: %d %d %d %d %d %d %d %d\n",nAnzahl2,nAnzahl1,nAnzahl05,nAnzahl02,nAnzahl01,nAnzahl005,nAnzahl002,nAnzahl001); } /*naiv*/ void mitGanzzahl(double nBetrag) { long long lBetrag=(long long)((nBetrag+0.004)*100); /*Ganzzahlwandlung und Runden*/ printf("Werte Euro/Cent: 2,00 1,00 0,50 0,20 0,10 0,05 0,02 0,01\n"); printf("Stueckelung: "); printf("%d ",lBetrag/200); lBetrag%=200; printf("%d ",lBetrag/100); lBetrag%=100; printf("%d ",lBetrag/50); lBetrag%=50; printf("%d ",lBetrag/20); lBetrag%=20; printf("%d ",lBetrag/10); lBetrag%=10; printf("%d ",lBetrag/5); lBetrag%=5; printf("%d ",lBetrag/2); lBetrag%=2; printf("%d\n",lBetrag); } /*mitGanzzahl*/ int main() { double nBetrag; do { printf("Bitte einen Betrag zwischen 0.01 und 5.00 Euro eingeben: "); fflush(stdin); /*in MSVC erlaubt*/ fscanf_s(stdin,"%lf",&nBetrag); /*Pruefung auf mehr als zwei Nachkommastellen fehlt noch*/ } while(nBetrag<=0||nBetrag>5.0); naiv(nBetrag); mitGanzzahl(nBetrag); system("Pause"); return 0; } /*main*/
Besonders die Anfänger sollten lernen, dass ihr Rechner falsch rechnet und gut ausgetestet werden muss. Schon folgender Test zeigt die Probleme:
Bitte einen Betrag zwischen 0.01 und 5.00 Euro eingeben: 0.03 Hier muss ein Rundungsfehler vorliegen: 1.000000e-002 Werte Euro/Cent: 2,00 1,00 0,50 0,20 0,10 0,05 0,02 0,01 Stueckelung: 0 0 0 0 0 0 1 0 Werte Euro/Cent: 2,00 1,00 0,50 0,20 0,10 0,05 0,02 0,01 Stueckelung: 0 0 0 0 0 0 1 1 Drücken Sie eine beliebige Taste . . .
Unser Wechsler betrügt uns in der ersten Variante immer um 1 Cent. Mit diesem Rundungstrick kann man Millionär werden.
Nichts für Ungut.
-
Deshalb nimmt man für solche (Währungen etc.) Probleme auch keinen Fließkommadatentyp wie float oder double.
-
Und darauf wird hier i.A auch hingewiesen.
Auch das Ganzzahlen keine geeigneten Datentypen für Postleitzahlen, Telfonnummern, Hausnummern und ... sind.
-
Ja, der DirkB ist da schon vorsichtig mit dem Zusatz i.A.
Aber in
http://www.c-plusplus.net/forum/311535
ist da kein Hinweis zu finden. Ich will auch nicht weitersuchen, denn sonst finde ich noch mehr Threads ohne diese Hinweise.
Aber jetzt soll es gut sein.
-
Man hat vom TE seitdem auch nichts mehr gelesen.
Ein Post, das wars.
Ob der Hinweis da dann überhaupt angekommt (nicht nur lesen, auch verstehen), bezweifele ich.
-
Waldschrat schrieb:
Aber in
http://www.c-plusplus.net/forum/311535
ist da kein Hinweis zu finden. Ich will auch nicht weitersuchen, denn sonst finde ich noch mehr Threads ohne diese Hinweise.
Dort, ebenso in vielen anderen Threads ohne diese Hinweise, geht es ja zunächst auch mal um etwas ganz anderes.