I am starting to make some progress on a decent fixed point library for C++. I know others exist, like the C fixed type in Allegro, but I plan to implement more and better mathematical functions than most of the simple alternatives. I want my type to be as close as possible to a drop-in replacement for float/double in an average game.
The negatives of fixed point math is that you have to decide on your range and precision ahead of time, which limits your options slightly when using a fixed point variable. For trig you may want a 0.31 type, giving a range of -1 to +1 with a precision of about .0000000005. For inverse trig, or other random handling of small numbers, 8.24 is a great type, -127 to +127 is the perfect range for binary angles, and 24 bits of decimal is one bit MORE than you get with a "0.23" float. 16.16 is your general purpose type, and the one I have implemented for benchmarking right now, which provides a range of 65536 and a precision of about .000015. 24.8 gives you very little decimal precision, about .004, but is handy for the few cases where you need 'big' numbes but also a couple of digits past the decimal place.
Eventually I would like a version of the library that defines multiple distinct types of different precisions and provides for correct promotion between them. That is a little ways off, definitely past having most of the functionality of libm provided.
Of course the positive of fixed point math is speed. Since we don't have a FPU we need to avoid floating point numbers like the plague. I wrote a little mandelbrot set generator for benchmarking my fixed type and the results are as follows for a 60x40 pixel image with 10000 iterations per pixel and an abort range of 4:
[root@gp2x sd]$./mandel-double
44008190
[root@gp2x sd]$./mandel-float
35858424
[root@gp2x sd]$./mandel-fixed
9254623
Translated... 44 seconds to draw the image using doubles, 36 seconds using floats, and 9 seconds using fixeds. With simple monochrome pixels the actual output of the fixed program differs from the float output on 8 pixels. That is a bit worrisome, until you consider that the float also differs from the double on 2 pixels. Chalk it up to rounding error. The fixed and float outputs are identical if I use 8.24 fixeds (compared to approx 2.21 floats), since the math in the mandelbrot algorithm doesn't require a large range, but I thought it would be fair to use 16.16 since that will be the norm.
I look forward to getting the library into a state where it can be used while porting existing games. Eventually I plan to revisit my Enigma port and see about moving the physics over to fixeds to resolve the FPS issue on physics-heavy levels like the meditation levels.
The negatives of fixed point math is that you have to decide on your range and precision ahead of time, which limits your options slightly when using a fixed point variable. For trig you may want a 0.31 type, giving a range of -1 to +1 with a precision of about .0000000005. For inverse trig, or other random handling of small numbers, 8.24 is a great type, -127 to +127 is the perfect range for binary angles, and 24 bits of decimal is one bit MORE than you get with a "0.23" float. 16.16 is your general purpose type, and the one I have implemented for benchmarking right now, which provides a range of 65536 and a precision of about .000015. 24.8 gives you very little decimal precision, about .004, but is handy for the few cases where you need 'big' numbes but also a couple of digits past the decimal place.
Eventually I would like a version of the library that defines multiple distinct types of different precisions and provides for correct promotion between them. That is a little ways off, definitely past having most of the functionality of libm provided.
Of course the positive of fixed point math is speed. Since we don't have a FPU we need to avoid floating point numbers like the plague. I wrote a little mandelbrot set generator for benchmarking my fixed type and the results are as follows for a 60x40 pixel image with 10000 iterations per pixel and an abort range of 4:
[root@gp2x sd]$./mandel-double
44008190
[root@gp2x sd]$./mandel-float
35858424
[root@gp2x sd]$./mandel-fixed
9254623
Translated... 44 seconds to draw the image using doubles, 36 seconds using floats, and 9 seconds using fixeds. With simple monochrome pixels the actual output of the fixed program differs from the float output on 8 pixels. That is a bit worrisome, until you consider that the float also differs from the double on 2 pixels. Chalk it up to rounding error. The fixed and float outputs are identical if I use 8.24 fixeds (compared to approx 2.21 floats), since the math in the mandelbrot algorithm doesn't require a large range, but I thought it would be fair to use 16.16 since that will be the norm.
I look forward to getting the library into a state where it can be used while porting existing games. Eventually I plan to revisit my Enigma port and see about moving the physics over to fixeds to resolve the FPS issue on physics-heavy levels like the meditation levels.