Fixed Math
Volume Number: 9
Issue Number: 10
Column Tag: C++ Workshop
Related Info: Binary-Dec. Pack.
Fast Fixed-point Math Made Easy
Using C++ to abstract data in an intuitive way
By Brion Sarachan, Albany, New York
Note: Source code files accompanying article are located on MacTech CD-ROM or
source code disks.
With the recent release of Symantec C++, a high-quality, low-cost C++
development environment is now available to Macintosh programmers. If used
properly, C++ can provide a quantum leap over the representation power of languages
like C and Pascal. We often hear about the use of C++ to build object-oriented
systems. Even more fundamentally, however, C++ is an excellent language for data
abstraction. Using C++, new data types can be defined that can then be used as
conveniently as the built-in types like integers, characters, and floating-point
numbers.
As an example of C++’s ability to support data abstractions, this article will
describe a simple C++ class for fixed-point numbers. Arithmetic operations on
fixed-point numbers are much faster than the corresponding operations on
floating-point numbers, at the expense of some loss in precision and a smaller range of
allowable values. Many computer graphics and animation applications that require
high-performance use fixed-point numbers.
Fixed-point numbers are not built into C++. The Mac Toolbox provides its own
implementation of fixed-point numbers. However, using the Mac’s fixed-point
numbers can be rather awkward for a couple of reasons:
• Arithmetic operators like * and / cannot be used. Instead, calls must be made to
Toolbox routines such as FixMul() and FixDiv(). Therefore, code that uses
fixed-point numbers must be written differently than other arithmetic
expressions.
• ANSI library functions such as sqrt() or printf() cannot use fixed-point
numbers directly. A fixed-point number must be converted to a double by using
functions like Fix2X() before using the library functions. This is even more
complicated because the manner in which fixed-point numbers are converted to
doubles may differ depending on the type of floating-point representation being
used by the processor or, if there is one, by the floating-point coprocessor.
C++ enables us to solve these problems by allowing us to define a new
fixed-point number class. This new class uses the Mac Toolbox internally, but allows
the programmer to declare fixed-point numbers and use them in expressions just as
easily as built-in types like ints or doubles.
The Macintosh Fixed Data Type and its Operations
The Macintosh Fixed data type is described in Inside Macintosh. A Fixed type is
actually a long integer:
typedef long Fixed;
A Fixed number therefore consists of 32 bits: a sign bit, a 15-bit integer part,
and a 16-bit fractional part. The value of a Fixed number therefore falls in the range
of about + and -32,768.
Fixed numbers can be added and subtracted using the usual + and - operators.
However, the * and / operators will not work correctly for multiplication and
division. Instead, the Toolbox provides the routines FixMul() and FixDiv(). The
Toolbox provides several other routines for conversion to and from other data types
and for some math functions. The following Toolbox routines are used in the
implementation of the C++ fixed-point number class:
• FixMul() - multiplies two fixed-point numbers
• FixDiv() - divides two fixed-point numbers
• FracSin() - returns the sine of a fixed-point number as a Fract
• FracCos() - returns the cosine of a fixed-point number as a Fract
• Frac2Fix() - converts a Fract to a fixed-point number
• Long2Fix() - converts a long integer to a fixed-point number
• X2Fix() - converts an extended-format floating-point number to a fixed-point
number
• Fix2X() - converts a fixed-point number to an extended-format floating-point
number
Some of these routines use something called a Fract. A Fract is an alternative
fixed-point type provided by the Toolbox. Like a Fixed number, a Fract also consists of
32 bits. However, for the case of a Fract, there is only one integer bit and a 30-bit
fractional part.
Normally, one would use fixed-point numbers by declaring Fixed variables and
calling the routines listed above directly. Using our new C++ class, we will be able to
use floating-point numbers much more easily, while still getting the benefit of fast
calculations.
C++ Features that Support Data Abstraction
C++ has several features that make it a good language for data abstraction. These
include:
• function overloading
• operator overloading
• user-defined type conversions
These features will be briefly described here, and they are discussed in depth in
many reference books on C++. (See the References section at the end of this article.)
Function overloading allows multiple functions having the same name to be
defined. As long as each instance of the function has a different argument type list, the
compiler is able to determine which instance is being called. Function overloading
allows us, for example, to define a sin() function, separate from the sin() function
found in the C library, that is specialized for our new fixed-point number class.
Operator overloading allows us to define the meaning of different types of
operators as they are applied to user-defined classes. This will allow us, for example,
to define the * and / operators for multiplication and division on our new fixed-point
number class.