Complex Division Patch (reprise)
Stephen L Moshier
moshier@mediaone.net
Fri Apr 30 22:47:00 GMT 1999
Here is the complex divide method from C9X.
[#8] EXAMPLE 2 Division of two double _Complex operands
could be implemented as follows.
#include <math.h>
#include <complex.h>
/* Divide z / w ... */
double complex _Cdivd(double complex z, double complex w)
{
#pragma STDC FP_CONTRACT OFF
double a, b, c, d, logbw, denom, x, y;
int ilogbw = 0;
a = creal(z); b = cimag(z);
c = creal(w); d = cimag(w);
logbw = logb(fmax(fabs(c), fabs(d)));
if (isfinite(logbw)) {
ilogbw = (int)logbw;
c = scalbn(c, -ilogbw);
d = scalbn(d, -ilogbw);
}
denom = c * c + d * d;
x = scalbn((a * c + b * d) / denom, -ilogbw);
y = scalbn((b * c - a * d) / denom, -ilogbw);
/*
* Recover infinities and zeros that computed
* as NaN+iNaN; the only cases are non-zero/zero,
* infinite/finite, and finite/infinite, ...
*/
if (isnan(x) && isnan(y)) {
if ((denom == 0.0) &&
(!isnan(a) || !isnan(b))) {
x = copysign(INFINITY, c) * a;
y = copysign(INFINITY, c) * b;
}
else if ((isinf(a) || isinf(b)) &&
isfinite(c) && isfinite(d)) {
a = copysign(isinf(a) ? 1.0 : 0.0, a);
b = copysign(isinf(b) ? 1.0 : 0.0, b);
x = INFINITY * ( a * c + b * d );
y = INFINITY * ( b * c - a * d );
}
else if (isinf(logbw) &&
isfinite(a) && isfinite(b)) {
c = copysign(isinf(c) ? 1.0 : 0.0, c);
d = copysign(isinf(d) ? 1.0 : 0.0, d);
x = 0.0 * ( a * c + b * d );
y = 0.0 * ( b * c - a * d );
}
}
return x + I * y;
}
[#9] Scaling the denominator alleviates the main overflow
and underflow problem, which is more serious than for
multiplication. In the spirit of the multiplication example
above, this code does not defend against overflow and
underflow in the calculation of the numerator. Scaling with
the scalbn function, instead of with division, provides
better roundoff characteristics.
More information about the Gcc-patches
mailing list