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
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
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