Nutzen von Fließkommazahlen



  • Für was werden denn Fließkommazahlen eingesetzt wenn sie so ungenau sind?

    Ich habe früher auf dem Amiga immer die Zahlen um einem festen Wert multipliziert und dann das Ergebniss eines Ausdrucks wieder durch die Zahl dividiert/geshiftet, das ging zwar auch nur bis zu einer bestimmten Genauigkeit aber es reichte für zum 3D-Grafiken aus.


  • Mod

    Für alles. Fließkommazahlen sind extrem genau. Überleg dir mal wie, genau Zahlen mit 15 zählenden Stellen sind. Damit kannst du ganz locker berechnen wie du auf der Erde eine Rakete abschießen musst, damit sie eine Fliege auf dem Mars genau zwischen die Augen trifft.



  • Naja, nein. Die Präzision hinterm Komma läßt extrem nach, wenn vor dem Komma was dazukommt.
    Fließkommazahlen für Währungsrechnunge zu nutzen grenzt schon an Kriminalität.



  • Ja davon habe ich auch schon gehört, ich meine das man Fließkommazahlen nicht mal für Buchhaltungsgeschichten einsetzen kann. Tja, wozu sind sie denn dann bloss zu gebrauchen bzw für was setzt ihr sie mit ruhigem Gewissen ein?


  • Administrator

    SeppJ schrieb:

    Für alles. Fließkommazahlen sind extrem genau. Überleg dir mal wie, genau Zahlen mit 15 zählenden Stellen sind. Damit kannst du ganz locker berechnen wie du auf der Erde eine Rakete abschießen musst, damit sie eine Fliege auf dem Mars genau zwischen die Augen trifft.

    Damit würde ich sehr aufpassen. Bei den C++ Fliesskommazahlen kommen schnell Rundungsfehler auf. Bei grösseren Zahlen wird es noch extremer, da können sogar ganze Zahlen verschluckt werden und verschwinden. Also für sowas würde ich Fliesskommazahlen definitiv nicht einsetzen, wäre mir zu gefährlich.
    Für Währungsrechnungen wurde es zum Teil eingesetzt, wegen des oben genannten Rundungsfehler aber inzwischen abgeschafft. Es gibt inzwischen bessere Fliesskommazahlen, welche sehr viel genauer sind und auch keine ungewollten Rundungen beinhalten. In C# gibt es zum Beispiel dazu System.Decimal . IEEE Standards wären hier 854-1987 und 754-2008 zu nennen.

    Dennoch haben Fliesskommazahlen ein grosses Einsatzgebiet. Schliesslich muss man nicht immer alles so ganz 100% genau haben. Gerade in Spielen ist es oftmals egal, ob etwas nun einen Pixel weiter links oder rechts liegt.
    Ich verwende Fliesskommazahlen oft auch für Prozentzahlen, wenn es mir egal ist, dass es nun einen kleinen Fehler gibt, weil dieser Fehler sich schlussendlich nicht auf das Programm auswirken wird, weil er zum Beispiel in der Darstellung verloren geht.
    Es gibt eben viele Einsatzgebiete, wo die Genauigkeit durchaus ausreicht 😉

    Grüssli



  • Welche Alternativen gibt es in C++ denn? Implementierungen oder wie? Die müssen doch letztlich auch mit dem selben Brot backen, oder nicht?!

    Gruß



  • theliquidwave schrieb:

    Welche Alternativen gibt es in C++ denn? Implementierungen oder wie? Die müssen doch letztlich auch mit dem selben Brot backen, oder nicht?!

    Kommt eben immer auf das Einsatzgebiet an.
    Nein - fließkommazahlen sind ja deshalb so toll, weil alle operationen in der hardware(fpu) ausgeführt werden.
    man hat ja noch die möglichkeit, sich etwas eigenes zu bauen.
    für geld-beträge bietet sich z.bsp. einfach nur eine ganz einfache lösung an:

    struct money_t
    {
    public:
      explicit money_t(int euro = 0, int cent = 0)
      : cent(euro*100+cent)
      {}
    
      int get_euro() const
      {
        return cent/100;
      }
      unsigned char get_cent() const
      {
        return unsigned char(cent%100);
      }
    private:
      int cent;
    };
    

    für unendlich genaue zahlen gibt es ja z.bsp. brüche (zumindest für die rationalen).
    für die irrationalen gibt es so und so keine genaue lösung...

    bb



  • In Cent rechnen ist eine gute Idee, aber man muss mit der Breite ein bisschen aufpassen - bei der Staatsverschuldung sind wir in Deutschland beispielsweise schon über einer Billion Euro, und 100 Billionen Cent kriegt man in einen 32-bit-Integer nicht mehr rein. Wie lange ein 64-bit-Integer reicht, bleibt abzuwarten. 😞


  • Administrator

    theliquidwave schrieb:

    Welche Alternativen gibt es in C++ denn? Implementierungen oder wie? Die müssen doch letztlich auch mit dem selben Brot backen, oder nicht?!

    Es gibt aber verschiedene Möglichkeiten, wie man backen kann 😉
    Unskilled und der Threadersteller haben bereits zwei Methoden genannt: Festkommazahl und Bruchdarstellung. Zudem gibt es noch die BCD Möglichkeit (Binary Coded Decimal). BCD erlaubt es grundsätzlich nur, beliebig grosse Zahlen darzustellen und mit ihnen zu rechnen. Dank der Methode der Festkommazahl kann man dann aber beliebig genaue und grosse Dezimalzahlen darstellen. Die einzige Grenze stellt dann die Performance und RAM-Speichergrösse dar. Wobei man natürlich auch auf die Festplatte ausweichen könnte, aber die Performance wäre dann noch schlimmer, als sie bereits durch BCD Zahlen ist. Es gibt zum Teil BCD Chips, aber ich glaube, dass die in einer Standard-CPU wohl kaum vorhanden sind.

    Grüssli



  • seldon schrieb:

    In Cent rechnen ist eine gute Idee, aber man muss mit der Breite ein bisschen aufpassen - bei der Staatsverschuldung sind wir in Deutschland beispielsweise schon über einer Billion Euro, und 100 Billionen Cent kriegt man in einen 32-bit-Integer nicht mehr rein. Wie lange ein 64-bit-Integer reicht, bleibt abzuwarten. 😞

    Bleibt abzuwarten? Nun, lange genug gewartet 😉 . Bei einem 64-Bit signed Integer (und den brauchst du für das Staatsguthaben 😃 ) ist der Maximalwert 2^63-1 und der Minimalwert -2^63. Also kann der Staat noch ca. 9223372035154775807 Euro Schulden machen. 😮



  • Hi,

    hier mal ein Beispiel wie ungenau ein float sein kann.

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        float a = 1.23456789f,
              b = 1.23f,
              c = 0.0f;
    
        c = a - b;
        cout << "a - b = " << c << endl;
    }
    

    Als Ergebnis sollte 0.00456789 rauskommen. Das Programm erzeugt bei mir stattdessen diese Ausgabe hier:

    a - b = 0.0045678[b]6[/b]
    

    Also Fließkommazahlen nur einsetzen wenn das Ergebnis auch mal leicht abweichen darf, ansonsten Festkomma etc. verwenden.

    G hibbes



  • _malsogefragt schrieb:

    Ja davon habe ich auch schon gehört, ich meine das man Fließkommazahlen nicht mal für Buchhaltungsgeschichten einsetzen kann. Tja, wozu sind sie denn dann bloss zu gebrauchen bzw für was setzt ihr sie mit ruhigem Gewissen ein?

    Bei allen naturwissenschaftlichen und ingenieurwissenschaftlichen Aufgaben! :p
    Hier sind float und double oft nahezu unverzichtbar. Habt ihr in der Schule auch nur mit ganzen Zahlen gerechnet? Zwischen je zwei ganzen Zahlen gibt es unendlich viele nichtganze Zahlen. Diese stellt man gewöhnlich als Fliesskommazahlen dar.

    Zwei sehr einfache Beispiele:
    1. die Berechnung des Schnittpunktes zweier Geraden.
    2. die Fläche innerhalb eines Polygons (Linienzug), z.B. zur Bestimmung einer Grundstücksgrösse im m².



  • Ich glaube der Threadersteller wollte wissen warum man Fließkommazahlen anstelle von Festkommazahlen verwendet. Beide können ja mit reellen Zahlen rechnen, nur sind die Fließkommazahlen dabei ungenau aber schnell, und die Festkommazahlen genau aber langsamer.

    Ich glaube gelesen zu haben das z.B. Taschenrechner nur mit Festkommazahlen arbeiten.

    G hibbes


  • Administrator

    @hibbes,
    Bisschen billig das Beispiel nicht? Da float nur auf maximal 7 Stellen genau sein kann, scheitert dein Beispiel bereits bei der Initialisierung von a . Statt die Rechnung durchzuführen und noch zwei weitere Variablen reinzunehmen, könntest du auch gleich a ausgeben.
    Wenn du dein Programm allerdings auf double umstellen würdest, wäre alles korrekt, da double auf maximal 16 Stellen genau ist.

    Hier vielleicht mal zwei sinnvolle Beispiele:

    int main()
    { 
      double a = 0.333;
      std::cout.precision(20);
    
      std::cout << (a * 3.0) << std::endl;
      // 0.33300000000000002 * 3.0 = 0.99900000000000011
    
      a = 1.0 / 3.0;
      std::cout << a << " * 3.0 = " << (a * 3.0) << std::endl;
      // 0.33333333333333331 * 3.0 = 1
    
      std::cin.get();
      return 0;
    }
    

    Beim ersten Beispiel sieht man gut, dass auch wenn man Zahlen nimmt, welche dargestellt werden können, es hinter den genauen Stellen Artefakte gibt.

    Das zweite Beispiel sieht zwar korrekt aus, ist aber zum Beispiel gerade bei Finanzen unerwünscht. Es gibt keine Möglichkeit eine Periode zu speichern. Somit sollte es hier nur ein 0.9999999999999999 ausgeben. In den Finanzen will man diese Rundung auf 1 selber durchführen und dies vor allem erst ganz am Schluss. Sonst wird die ganze Zeit in den Rechnungen bereits gerundet, was am Ende zu einem Rundungsfehler führt.
    Meine bisherigen Erfahrungen haben gezeigt, dass dieser Rundungsfehler schnell mal 2-3 Cent ausmachen kann, bei noch relativ kleinen Beträgen (< 1 Mio).

    Grüssli



  • hibbes schrieb:

    und die Festkommazahlen genau aber langsamer.

    Je nach dem, was man macht. Hat man es viel mit Addition und Subtraktion zu tun, sind Festkommazahlen so schnell wie int.

    Ich glaube gelesen zu haben das z.B. Taschenrechner nur mit Festkommazahlen arbeiten.

    Ich weiß nicht. Mir sehen die http://www.oldcalculatormuseum.com/ nach Fließkommazahlen aus.



  • @Dravere: ja hast recht, mein Beispiel war Mist :p

    @Volkard: das sind ja mal ein paar Rechenmaschinen, wo kommen da die Clowns raus? 😃



  • wxSkip schrieb:

    seldon schrieb:

    In Cent rechnen ist eine gute Idee, aber man muss mit der Breite ein bisschen aufpassen - bei der Staatsverschuldung sind wir in Deutschland beispielsweise schon über einer Billion Euro, und 100 Billionen Cent kriegt man in einen 32-bit-Integer nicht mehr rein. Wie lange ein 64-bit-Integer reicht, bleibt abzuwarten. 😞

    Bleibt abzuwarten? Nun, lange genug gewartet 😉 . Bei einem 64-Bit signed Integer (und den brauchst du für das Staatsguthaben 😃 ) ist der Maximalwert 2^63-1 und der Minimalwert -2^63. Also kann der Staat noch ca. 9223372035154775807 Euro Schulden machen. 😮

    Och, das kriegt der im nächsten Jahrhundert noch hin. Wir befinden uns bei Verzinsung ja im Bereich von Exponentialfunktionen.

    Wie dem auch sei, Fließkommazahlen können ganz andere Bereiche abdecken als Festkommazahlen gleicher Größe, und es gibt viele Anwendungen, in denen es auf ein paar Millionen nicht ankommt, wenn man gerade mit Trilliarden in der Gegend rumjongliert. Gleichzeitig werden Fließkommazahlen bei sehr kleinen Beträgen überaus genau - man mag zwar selten mit Mikrocent rechnen müssen, aber Nanometer können durchaus mal vorkommen.



  • wxSkip schrieb:

    seldon schrieb:

    In Cent rechnen ist eine gute Idee, aber man muss mit der Breite ein bisschen aufpassen - bei der Staatsverschuldung sind wir in Deutschland beispielsweise schon über einer Billion Euro, und 100 Billionen Cent kriegt man in einen 32-bit-Integer nicht mehr rein. Wie lange ein 64-bit-Integer reicht, bleibt abzuwarten. 😞

    Bleibt abzuwarten? Nun, lange genug gewartet 😉 . Bei einem 64-Bit signed Integer (und den brauchst du für das Staatsguthaben 😃 ) ist der Maximalwert 2^63-1 und der Minimalwert -2^63. Also kann der Staat noch ca. 9223372035154775807 Euro Schulden machen. 😮

    Sollte man sich dann nicht mal überlegen, ob man die Gleitkomma-Arithmetik anpaßt,
    so dass Deutschland :schland: nach einem Überlauf wieder schuldenfrei ist? 🤡



  • Also wenn ich mir so den Wikipediaartikel durchlese muss man gar nicht in einen Mikrocentbreich gehen um mit Fließkommazahlen böse Überraschungen zu erleben. In dem Artikel sind Punkte aufgeführt wie:

    - Auslöschung
    - Zahlen verschiedener Größenordnungen
    - Unterlauf
    - Ungültigkeit des Assoziativgesetzes
    - Ungültigkeit des Distributivgesetzes

    http://de.wikipedia.org/wiki/Gleitkommazahl

    Ich habe mal das mit den verschiedenen Größenordnungen getestet und wenn ich nix falsch gemacht habe würde ich nie und nimmer die Fließkommazahlen für kaufmännische Rechnungen einsetzten wollen. Für Gleichungen scheinen sie auch nicht so geeignet zu sein wie im Artikel steht.

    #include <iostream>
    
    int main()
    {
        double a = 1000,
               b = 0.001,
               c = 0.0;
    
        c = a + b;
        std::cout << "a + b = " << c << std::endl;
    }
    

    Ausgabe ist hier 1000 und nicht 1000.001 und das bei double 😮 . Ich muss da mal wieder einen Fehler gemacht haben, oder?

    G hibbes



  • hibbes schrieb:

    #include <iostream>
    
    int main()
    {
        double a = 1000,
               b = 0.001,
               c = 0.0;
    
        c = a + b;
        std::cout << "a + b = " << c << std::endl;
    }
    

    Ausgabe ist hier 1000 und nicht 1000.001 und das bei double 😮 . Ich muss da mal wieder einen Fehler gemacht haben, oder?

    Ja, std::cout verwendet.

    int main()
    {
        double a = 1000,
               b = 0.001,
               c = 0.0;
    
        c = a + b;
        printf("%f", c);
    }
    

Log in to reply