C/C++ Users Journal December, 2004
Fixed-point arithmetic seems to be practically a lost art. Yes, I know the term is often applied to integer arithmetic, to distinguish it from floating point. But that's just a special case. The more general case is a representation that maintains a fixed number of fraction digits. For a decimal encoding, they're decimal digits to the right of a decimal point; for a binary encoding, they're bits to the right of a binary point.
Floating point, by contrast, maintains a fixed number of significant digits, plus an exponent that provides for a very wide range of values. You can do a lot with floating-point arithmetic, but at a cost. Operations are much more complex, and hence slower. Moreover, that varying exponent means that values are represented with varying granularityÑthey bunch together near zero and spread ever more widely for large magnitudes. That makes for all sorts of computational pitfalls that I've come to learn and fear over the past four decades.
So why would you ever use fixed point instead? If you can live with a (much) more tightly bounded range of values, or if you need the more uniform granularity, or if you just plain need greater speed, then fixed point can be just the ticket. There's still a lot of shifting going on, to align fractions of different length, and there are issues of overflow fixup and suitable rounding to deal with when you use such values. Nevertheless, fixed point can be a big win for a variety of needs.
The overt evidence is that this list of needs doesn't often arise anymore. Floating point is so darned fast, and it's now standard on so many modern CPUs. (It has been optional on smaller chips because it takes about as much microcode to do floating add, subtract, multiply, and divide as it does all the rest of a typical modest instruction set.) The last major languages that offer built-in fixed-point data types were Cobol and PL/I, neither of which is used for much new code development these days. Given my reputation as a math wonk, you might dismiss an interest in fixed point as just another of my obsessions. (And I won't deny that there's some truth in that.)
But if you do some forms of embedded programming, you might know about an important netherworld. It's one that lurks just below "C" level, as it were. Unless someone has provided suitable language extensions, that is. And it's terribly important in today's world. I'm talking, of course, about digital signal processing, or DSP for short.
DSP is a general term for manipulating a stream of digitized samples, mostly by doing simple arithmetic on local clusters of values (with a bit of memory thrown in for What Has Gone Before). And most of that arithmetic often turns out to be a sequence of fixed-point multiplies and adds. If you've never studied DSP, you'll probably be astonished at what you can do with multiplies, adds, and a few tables of coefficients. You can make a high-pass filter or a low-pass one. You can generate touch tones, or detect them. You can, in fact, make all those whistles and clacks that modems do when they're negotiating a protocol, and then swapping bits reliably.
There are lots of specialized DSP chips out there in embedded land. Some also look enough like general-purpose computers that you can embed DSP magic instructions in stuff that looks otherwise like C, or even C++. In fact, most of the heavy-duty processors in modern desktops have a few DSP instructions bolted onto the more conventional ones you studied in Comp Sci 201. Luckily for the programmers who have to make them perform, it's getting more commonplace for a new DSP to support some dialect of C, sometimes even Standard C.
So now the C Standards committee is repaying the compliment. They've recently got approval for something called "Technical Report 18037." (See the final draft at http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1021.pdf.) It's a nonnormative description of several bolt-ons for C to better support embedded programming. The biggest single chunk is a set of language and library additions for doing fixed-point arithmetic. It was originally developed by ACE Associated Computer Experts in the Netherlands, so it saw some real-world use before it got standardized. And, no surprise, it is flexible enough to accommodate most of the DSPs in use today that support any reasonable dialect of C.
I've coded the library support both as a set of C++ templates and as a C runtime for use with the Edison Design Group front end, which now supports the language additions. With a DSP underneath it can be really fast, but even without special hardware it still goes. And it sure beats doing fixed-point arithmetic in assembly language. Or PL/I.
P.J. Plauger
Senior Editor
pjp@plauger.com