Seite 1 von 1

Problem mit Fließkommazahlen

Verfasst: Do Mai 28, 2020 10:57 am
von Santuciy
Guten Tag!

Heute habe ich mein erstes C-Programm geschafft!
Jedoch bleibt ein Problem ungelöst, das ich als Anfänger nicht verstehen kann und um dessen Lösung ich bitte.

Im flogenden Programm entsteht ein Problem mit Fließkommazahlen in float.
Die Ein- und Ausgabezahlen werden zufälligerweise verändert.

Bei der Ausführung sieht es so aus:

Bild

Meine Fragen sind:
Warum ist der durch scanf() eingegebene Wert 333.329987 und nicht 333.330000?
Warum ist der gerundete Wert 166.660004 und nicht 166.660000?
Wie lässt sich das Problem lösen?

Der Code:

Code: Alles auswählen

#include <stdio.h>

void Umrechnung();

float Runden001(float);

int main()
{
    int eingabe=0;
    printf("Das Programm zur Umrechnung DM - Euro.\n\n");
    do
        {
            Umrechnung();
            printf("Geben Sie \"1\" ein, um noch eine Umrechnung zu machen.\n");
            printf("Geben Sie \"0\", um das Programm zu beenden: ");
            scanf("%d", &eingabe);
        }
    while(eingabe!=0);
        return 0;
}

void Umrechnung ()
{
    float DMBetrag=0, EuroBetrag=0;
    printf("\nGeben Sie den Betrag in DM ein: ");
    scanf("%f", &DMBetrag);
    EuroBetrag=(DMBetrag/2);
    printf("\n%f DM entsprechen %f Euro.\n\n", DMBetrag, Runden001(EuroBetrag));
}

float Runden001(float zahl)
{
    float ergebnis=(((float)((int)((zahl+0.005)*100)))/100);
    return ergebnis;
}
Ich danke im Voraus für die Hilfe!

Re: Problem mit Fließkommazahlen

Verfasst: Do Mai 28, 2020 11:36 am
von cloidnerux
Hallo und Willkommen im Forum,

zu allem gibt es ein XKCD, so auch hier: https://xkcd.com/217/
Das Problem ist Fließkomma-Genauigkeit. Floats und Doubles(Fließkommezahlen) werden im Computer in der Form x*2^y gespeichert, daher ein "fester" Teil x und ein Exponent y. Dies entspricht der wissenschaftlichen Zahlennotation 3.45*10^3 z.B. Dies hat den Vorteil, dass extrem kleine und auch extrem große Zahlen gehandhabt werden können, aber leider auch den Nachteil, dass dies nur Näherungen sind, da die Genauigkeit des festen Teiles x beschränkt ist.

In vielen Finanzsystemen, wo man diese Rundungen absolut nicht haben möchte verwendet man Festkommazahlen, daher ein Zahlenformat mit einer festen Breite vor und nach dem Komma. Dies verhindert die Rundungsprobleme, ist aber nicht so flexibel.

Re: Problem mit Fließkommazahlen

Verfasst: Fr Mai 29, 2020 10:16 am
von Santuciy
Vielen Dank für Ihre Erklärung, cloidnerux!

Dank Ihrem Hinweis auf die Festkommazahlen habe ich eine Lösung konkret für meinen Fall gefunden und zwar hier: https://www.mikrocontroller.net/topic/87745.
Anstatt DM und Euro als Fließkommazahlen darzustallen und damit zu rechnen, habe ich alle interne Rechnungen mit Cent gemacht und so die Fließkommazahlen und folgende Rundungsfehler vermieden.

Falls ein Suchender meinen Code brauchen wird, sieht die Umrechungsfunktion so aus:

Code: Alles auswählen

void Umrechnung ()
{
    int DMBetrag=0, DMCentBetragE=0, DMCentBetragI=0, EuroBetrag=0, EuroCentBetragI=0, EuroCentBetragE=0;   /*  Berechnungen erfolgen nur mit Cent,
                                                                                                                um Rundungen von Fließkommazahlen zu vermeiden
                                                                                                                I - interner (Rechnungs-)Wert; E - externer (Aus- /Input-)Wert */
    printf("\nGeben Sie den Betrag in DM im Format Mark.CC ein: ");
    scanf("%d.%d", &DMBetrag, &DMCentBetragE);

    DMCentBetragI=DMCentBetragE+(DMBetrag*100);
    EuroCentBetragI=(DMCentBetragI/2);
    EuroBetrag=EuroCentBetragI/100;
    EuroCentBetragE=EuroCentBetragI-(EuroBetrag*100);

    printf("\n%d.%d DM entsprechen %d.%d Euro.\n\n",DMBetrag,DMCentBetragE,EuroBetrag,EuroCentBetragE);
}
Ich musste auch für die Schleife zusätzlich den Eingabepuffer mit fflush(stdin) löschen.

Re: Problem mit Fließkommazahlen

Verfasst: Sa Mai 30, 2020 6:30 am
von mfro
Das fflush(stdin) solltest Du dir nicht angewöhnen.

Auch wenn's auf manchen Plattformen (für stdin) funktioniert, ist es auf den meisten undefined behaviour. Und selbst wenn's (wie bei Windows) dokumentiert (und damit implementation defined) ist, ist es doch wenigstens unlogisch.

Man löscht einen Input-Stream, indem man alle anstehenden Zeichen liest.

Re: Problem mit Fließkommazahlen

Verfasst: Sa Mai 30, 2020 4:23 pm
von Xin
Santuciy hat geschrieben:
Do Mai 28, 2020 10:57 am
Warum ist der durch scanf() eingegebene Wert 333.329987 und nicht 333.330000?
Warum ist der gerundete Wert 166.660004 und nicht 166.660000?
Zahlendarstellung auf dem Computer
Santuciy hat geschrieben:
Do Mai 28, 2020 10:57 am
Wie lässt sich das Problem lösen?
Man kann Fix-Point-Zahlen nehmen. Das sind praktisch Integers, denen man eine andere Einheit gibt.
Statt 1,00 Euro kann man 100 Cent nehmen. Oder 10000 Hundertstel-Cent.

Re: Problem mit Fließkommazahlen

Verfasst: Di Jun 02, 2020 3:44 pm
von Santuciy
Danke für den Ratschlag, mfro!
Man löscht einen Input-Stream, indem man alle anstehenden Zeichen liest.
Diese Zeile habe ich zwar nicht ganz nachvollzogen, habe aber fflush(stdin) durch

Code: Alles auswählen

while(getchar()=='/n'&&getchar()==EOF)
            {
                ;
            }
ersetzt und alles lief einwandfrei.

double?

Verfasst: Di Okt 27, 2020 1:58 pm
von Xeon
Hallo Santuciy

Etwas spät aber ich möchte trotzdem etwas dazu sagen.

Hier die Kurzversion von deinem Code:

Code: Alles auswählen

#include <stdio.h>


int main()
{
  float DM = 333.330000;
  float Euro = 166.660000;

  printf("%f\n", DM);
  printf("%f\n", Euro);

  return 0;
}

Die Ausgabe ist wie bei dir: DM = 333.329987, Euro = 166.660004

Jetzt das Selbe mit dem Datentyp double:

Code: Alles auswählen

#include <stdio.h>


int main()
{
  double DM = 333.330000;
  double Euro = 166.660000;

  printf("%f\n", DM);
  printf("%f\n", Euro);

  return 0;
}
Die Ausgabe ist jetzt bei mir wie gewünscht: DM = 333.330000, Euro = 166.660000

float ist einfach zu klein, um so eine große Zahl darzustellen.


Liebe Grüße
Von Xeon

Re: Problem mit Fließkommazahlen

Verfasst: Di Okt 27, 2020 3:45 pm
von Xin
Es kann sein (und ich halte es für wahrscheinlich), dass die Darstellung in Double nicht anders ist als in float. Nur dass die Ungenauigkeiten weiter hinter dem Komma entstehen und bei der Darstellung mit 6 Nachkommastellen weggerundet werden.
Fließkommazahlen sind immer ungenau und nur ein Kompromiss.