31 Oct 2007
Posted by Manuel at 22:35 — 1 year, 2 months ago
Categories: c++, dev
NOTE
This post has been previously published on 2007/Oct/31: due to my move to another server i’m now in the process to manually recover the comments for this article. Fixed!
Some time ago i was asked to publish my implementation of fixed-point math, mainly regarding embedded architectures where IEEE floating point computations have really bad performances. What i want to give you here is a pure-c++, template-based implementation of a fixed-point datatype: this thing is more of a test in order to see how much an object-oriented implementation can perform, being in contrast to a more traditional implementation. As expected, operator overloading and temporary object creation overhead are the main issues with a full-oo implementation as this one, anyway, its a damn nice way to exercise yourself in writing c++ policy-based templated code ;)
Big thank you goes to Kurt for having a great discussion with me on c++, math and for recommending me the most wonderful book on computer arithmetic as Hacker’s Delight delivers it in spades!
Back to the fp stuff: usage of this code in testing environments is advised, since it could contain rounding errors and sometimes explicit casts are needed to get it to work correctly; as i said, this was some sort of test, i abandoned the O-O idea when i ack the performances’ gap between OO vs. traditional implementation was remarkable (at least on embedded devices).
Before showing some usage guidelines, i should say that using this datatype on a desktop machine hasn’t much sense: nowadays floating-point math is faster than the integer’s one!
The class itself predefines a 24.8 and a 16.16:
typedef AquaFixed< 8, LowPrecision, LowPrecision> fixed8_t; typedef AquaFixed<16, HighPrecision, HighPrecision> fixed16_t;
An usage example could be a generic, datatype-unaware Matrix implementation as this one:
template<class Number>
class matrix {
private:
Number m[4][4];
public:
matrix();
// matrix indexing
inline Number&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; operator()(const int,const int);
// matrix operations
matrix<Number> operator*(const matrix<Number>);
matrix<Number> operator/(const matrix<Number>);
};
Doing it this way, you should be able to declare a Matrix as here and perform your own tests:
matrix<float_t> float_matrix; matrix<fixed16_t> fixed_matrix;
NOTE! The AquaFixed class comes out straight from my framework, so you’ll have to define basic datatypes such as int32_t/int64_t for yourself, but that shouldn’t be a problem.
Get the code here and let me know of your tests!
2 Responses
Kurt Guntheroth
December 3rd, 2007 at 21:43 1I am the “Kurt” referenced in the article. My experience is that fixed-point costs about 15% more than integer math, and is about twice as fast as floating point math on Intel Pentium-4 processors, and using Microsoft visual c++ versions from 6 to .Net-2005.
In evaluating the performance of fixed point arithmetic routines, it is important to compile a “release” build. On debug builds, the compiler creates function calls for all your template functions. Function call overhead eats the performance gains from using fixed point.
Manuel
December 5th, 2007 at 23:21 2Thank you for your feedback Kurt: i performed various test at the time on a desktop machine, obviously with a release build, but on a Pentium D i didn’t notice improvements at all, floating point was showily faster than anything else.
It may be possible that my tests weren’t exhaustive as they should, i used a matrix-based test and a 3d rasterizer: both tests showed up big fixed point improvements on mobile platforms but none on the desktop.
I’ll try to search my old tests, too bad i don’t think i still have what i used at the time..
Have you played with compiling/linking options and stuff like that?
Leave a reply