Festkommazahl

Die Festkommazahl wird in Bereichen verwendet, in denen die CPU-Architektur keine bzw. nur langsame Fließkommazahlen anbietet oder wo die Präzision des Ergebnisses wichtig ist. Häufig in verschiedener Hardware eingegossen, da einfacher zu handhaben als Fließkommazahlen, in älteren Spielen und im Finanzbereich zu finden.

Beispiel (Quellcode): fixedpoint.cpp
Download (Quellcode): fixedpoint.zip

Beschreibung

Beispiel für Festkommazahl in dezimaler und binärer Ausführung Die Festkommazahl wird durch eine Ganzzahl gehalten, die mindestens so groß sein muss, dass sie die Stellenanzahl (Vor- und Nachkommastellen) aufnehmen kann. Auch die Genauigkeit hängt direkt von der Anzahl der Nachkommastellen ab, daher wird hier meist der Mittelweg zwischen der Größe der Ganzzahl und der Genauigkeit gesucht. Häufig wird zwischen binären und dezimalen Festkommazahlen unterschieden, obwohl natürlich alle möglichen Basen benutzt werden können. Wenn die richtige Basis gewählt ist, besteht die Möglichkeit ohne Rundung eine Zahl vom möglichen Zahlenbereich aufzunehmen.

Unabhängig davon was für eine Art der Festkommazahl benutzt wird, gibt es einen Multiplikator. Dieser Multiplikator hebt die Nachkommastellen in den benutzbaren Bereich der Ganzzahl. Bei Festkommazahlen zur Basis 2 (also den Binären) ist es auch möglich Bitverschiebungen zu benutzen. Alle primitiven Operationen an der Festkommazahl, können wie mit einer Ganzzahl erledigt werden. Jedoch muss bei der Division und Multiplikation aufgepasst werden, da sich dort der Multiplikator erhöht oder verringert. Dies kann zu Präzisionsverlusten führen. Sollen Festkommazahlen unterschiedlicher Multiplikatoren und/oder Basen miteinander verrechnet werden, muss eine der Beiden umgewandelt werden.

Es ist natürlich auch möglich einen negativen Multiplikator zu verwenden, so dass keine Nachkommastellen vorhanden sind, aber der Wertebereich der Zahl größer wird.

Durch den Beispielcode

Der Beispielcode, enthält ein Klassentemplate (C++), das eine Festkommazahl mit verschiedenen Multiplikatoren und Ganzzahlen bilden kann:

  • der Konstruktor

    CFixedPoint() : m_nNumber(0) {}
    CFixedPoint(_TYPE nNumber) : m_nNumber(nNumber) {}
    CFixedPoint(const CFixedPoint& other) : m_nNumber(other.m_nNumber) {}
    CFixedPoint(float fValue) : m_nNumber((_TYPE)(fValue*(float)_MULTIPLICATOR)) {}
    CFixedPoint(double fValue) : m_nNumber((_TYPE)(fValue*(double)_MULTIPLICATOR)) {}
    18
    19
    20
    21
    22
    

    Beim Erzeugen der Klasse, muss der Multiplikator, der Ganzzahltyp sowie der Typ angegeben werden, der eine Multiplikation ohne Überlauf zulässt.

  • Operatoren/Vergleich

    Die Klassen kann durch Operatorüberladungen, mit wenigen Ausnahmen, wie eine ganz gewöhnliche Fließkommazahl benutzt werden.

Codeanmerkungen

  1. Die Aufrufparameter des Programms bilden Werte die Verrechnet und Verglichen werden, alle hier zur Basis zehn mit drei Nachkommastellen:

    std::vector<CFixedPoint<int, int64_t, 1000> > numbers;
    for(int n=1; n<argc; n++)
      numbers.push_back(atof(argv[n]));
    91
    92
    93
    

    So ergibt

    ./fixedpoint 0.1 1 10
    

    die Ausgabe

    Fixed point number...
    
     Multiplication:
      0.100 * 1.000 = 0.100
      0.100 * 10.000 = 1.000
      1.000 * 0.100 = 0.100
      1.000 * 10.000 = 10.000
      10.000 * 0.100 = 1.000
      10.000 * 1.000 = 10.000
    
     Division:
      0.100 / 1.000 = 0.100
      0.100 / 10.000 = 0.010
      1.000 / 0.100 = 10.000
      1.000 / 10.000 = 0.100
      10.000 / 0.100 = 100.000
      10.000 / 1.000 = 10.000
    
     Modulo:
      0.100 % 1.000 = 0.100
      0.100 % 10.000 = 0.100
      1.000 % 0.100 = 0.000
      1.000 % 10.000 = 1.000
      10.000 % 0.100 = 0.000
      10.000 % 1.000 = 0.000
    
     Equality:
      0.100 == 1.000 = false
      0.100 == 10.000 = false
      1.000 == 0.100 = false
      1.000 == 10.000 = false
      10.000 == 0.100 = false
      10.000 == 1.000 = false
    
     Greater than:
      0.100 > 1.000 = false
      0.100 > 10.000 = false
      1.000 > 0.100 = true
      1.000 > 10.000 = false
      10.000 > 0.100 = true
      10.000 > 1.000 = true