Next: Round-Trip Base Conversion, Previous: Machine Epsilon, Up: Floating Point in Depth [Contents][Index]
We’ve already looked at defining and referring to complex numbers (see Complex Data Types). What is important to discuss here are some issues that are unlikely to be obvious to programmers without extensive experience in both numerical computing, and in complex arithmetic in mathematics.
The first important point is that, unlike real arithmetic, in complex arithmetic, the danger of significance loss is pervasive, and affects every one of the basic operations, and almost all of the math-library functions. To understand why, recall the rules for complex multiplication and division:
a = u + I*v /* First operand. */ b = x + I*y /* Second operand. */ prod = a * b = (u + I*v) * (x + I*y) = (u * x - v * y) + I*(v * x + u * y) quo = a / b = (u + I*v) / (x + I*y) = [(u + I*v) * (x - I*y)] / [(x + I*y) * (x - I*y)] = [(u * x + v * y) + I*(v * x - u * y)] / (x**2 + y**2)
There are four critical observations about those formulas:
Another point that needs careful study is the fact that many functions
in complex arithmetic have branch cuts. You can view a
function with a complex argument, f (z)
, as f (x + I*y)
,
and thus, it defines a relation between a point (x, y)
on the
complex plane with an elevation value on a surface. A branch cut
looks like a tear in that surface, so approaching the cut from one
side produces a particular value, and from the other side, a quite
different value. Great care is needed to handle branch cuts properly,
and even small numerical errors can push a result from one side to the
other, radically changing the returned value. As we reported earlier,
correct handling of the sign of zero is critically important for
computing near branch cuts.
The best advice that we can give to programmers who need complex arithmetic is to always use the highest precision available, and then to carefully check the results of test calculations to gauge the likely accuracy of the computed results. It is easy to supply test values of real and imaginary parts where all five basic operations in complex arithmetic, and almost all of the complex math functions, lose all significance, and fail to produce even a single correct digit.
Even though complex arithmetic makes some programming tasks easier, it may be numerically preferable to rework the algorithm so that it can be carried out in real arithmetic. That is commonly possible in matrix algebra.
GNU C can perform code optimization on complex number multiplication and
division if certain boundary checks will not be needed. The
command-line option -fcx-limited-range tells the compiler that
a range reduction step is not needed when performing complex division,
and that there is no need to check if a complex multiplication or
division results in the value Nan + I*NaN
. By default these
checks are enabled. You can explicitly enable them with the
-fno-cx-limited-range option.
Next: Round-Trip Base Conversion, Previous: Machine Epsilon, Up: Floating Point in Depth [Contents][Index]