* Copyright (c) 1993 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
* Extended precision complex arithmetic non-primitive routines
* Round a complex number to the specified number of decimal places.
* This simply means to round each of the components of the number.
* Zero decimal places means round to the nearest complex integer.
COMPLEX
*res
; /* result */
res
->real
= qround(c
->real
, places
);
res
->imag
= qround(c
->imag
, places
);
* Round a complex number to the specified number of binary decimal places.
* This simply means to round each of the components of the number.
* Zero binary places means round to the nearest complex integer.
COMPLEX
*res
; /* result */
res
->real
= qbround(c
->real
, places
);
res
->imag
= qbround(c
->imag
, places
);
* Compute the result of raising a complex number to an integer power.
COMPLEX
*c
; /* complex number to be raised */
NUMBER
*q
; /* power to raise it to */
COMPLEX
*tmp
, *res
; /* temporary values */
long power
; /* power to raise to */
unsigned long bit
; /* current bit value */
math_error("Raising number to non-integral power");
math_error("Raising number to very large power");
power
= (zistiny(q
->num
) ? z1tol(q
->num
) : z2tol(q
->num
));
if (ciszero(c
) && (power
== 0))
math_error("Raising zero to zeroth power");
* Handle some low powers specially
switch ((int) (power
* sign
)) {
* Compute the power by squaring and multiplying.
* This uses the left to right method of power raising.
while ((bit
& power
) == 0)
* Calculate the square root of a complex number, with each component
* within the specified error. If the number is a square, then the error
* is zero. For sqrt(a + bi), this calculates:
* U = sqrt((R + abs(a))/2)
* then sqrt(a + bi) = U + Vi if a >= 0,
* or abs(V) + sgn(b) * U if a < 0
NUMBER
*A
, *B
, *R
, *U
, *V
, *tmp1
, *tmp2
, *epsilon2
;
if (ciszero(c
) || cisone(c
))
r
->real
= qsqrt(c
->real
, epsilon
);
r
->imag
= qsqrt(tmp1
, epsilon
);
n
= zhighbit(B
->num
) - zhighbit(B
->den
);
m
= zhighbit(A
->num
) - zhighbit(A
->den
);
epsilon2
= qscale(epsilon
, n
/2);
R
= qhypot(A
, B
, epsilon2
);
tmp2
= qscale(tmp1
, -1L);
U
= qsqrt(tmp2
, epsilon
);
* Take the Nth root of a complex number, where N is a positive integer.
* Each component of the result is within the specified error.
NUMBER
*a2pb2
, *root
, *tmp1
, *tmp2
, *epsilon2
;
if (qisneg(q
) || qiszero(q
) || qisfrac(q
))
math_error("Taking bad root of complex number");
if (cisone(c
) || qisone(q
))
return csqrt(c
, epsilon
);
if (cisreal(c
) && !qisneg(c
->real
)) {
r
->real
= qroot(c
->real
, q
, epsilon
);
* Calculate the root using the formula:
* cpolar(qroot(a^2 + b^2, 2 * n), qatan2(b, a) / n).
epsilon2
= qscale(epsilon
, -8L);
a2pb2
= qadd(tmp1
, tmp2
);
root
= qroot(a2pb2
, tmp1
, epsilon2
);
tmp1
= qatan2(c
->imag
, c
->real
, epsilon2
);
r
= cpolar(root
, tmp2
, epsilon
);
* Calculate the complex exponential function to the desired accuracy.
* exp(a + bi) = exp(a) * (cos(b) + i * sin(b)).
NUMBER
*tmp1
, *tmp2
, *epsilon2
;
r
->real
= qexp(c
->real
, epsilon
);
epsilon2
= qscale(epsilon
, -2L);
r
->real
= qcos(c
->imag
, epsilon2
);
r
->imag
= qlegtoleg(r
->real
, epsilon2
, _sinisneg_
);
tmp1
= qexp(c
->real
, epsilon2
);
tmp2
= qmul(r
->real
, tmp1
);
tmp2
= qmul(r
->imag
, tmp1
);
* Calculate the natural logarithm of a complex number within the specified
* error. We use the formula:
* ln(a + bi) = ln(a^2 + b^2) / 2 + i * atan2(b, a).
NUMBER
*a2b2
, *tmp1
, *tmp2
;
math_error("Logarithm of zero");
if (cisreal(c
) && !qisneg(c
->real
)) {
r
->real
= qln(c
->real
, epsilon
);
tmp1
= qln(a2b2
, epsilon
);
r
->real
= qscale(tmp1
, -1L);
r
->imag
= qatan2(c
->imag
, c
->real
, epsilon
);
* Calculate the complex cosine within the specified accuracy.
* cos(a + bi) = cos(a) * cosh(b) - sin(a) * sinh(b) * i.
NUMBER
*cosval
, *coshval
, *tmp1
, *tmp2
, *tmp3
, *epsilon2
;
r
->real
= qcos(c
->real
, epsilon
);
r
->real
= qcosh(c
->imag
, epsilon
);
epsilon2
= qscale(epsilon
, -2L);
coshval
= qcosh(c
->imag
, epsilon2
);
cosval
= qcos(c
->real
, epsilon2
);
r
->real
= qmul(cosval
, coshval
);
* Calculate the imaginary part using the formula:
* sin(a) * sinh(b) = sqrt((1 - a^2) * (b^2 - 1)).
r
->imag
= qsqrt(tmp2
, epsilon2
);
* Calculate the complex sine within the specified accuracy.
* sin(a + bi) = sin(a) * cosh(b) + cos(a) * sinh(b) * i.
NUMBER
*cosval
, *coshval
, *tmp1
, *tmp2
, *epsilon2
;
r
->real
= qsin(c
->real
, epsilon
);
r
->imag
= qsinh(c
->imag
, epsilon
);
epsilon2
= qscale(epsilon
, -2L);
coshval
= qcosh(c
->imag
, epsilon2
);
cosval
= qcos(c
->real
, epsilon2
);
tmp1
= qlegtoleg(cosval
, epsilon2
, _sinisneg_
);
r
->real
= qmul(tmp1
, coshval
);
tmp1
= qsqrt(tmp2
, epsilon2
);
r
->imag
= qmul(tmp1
, cosval
);
* Convert a number from polar coordinates to normal complex number form
* within the specified accuracy. This produces the value:
* q1 * cos(q2) + q1 * sin(q2) * i.
NUMBER
*q1
, *q2
, *epsilon
;
if (qiszero(q1
) || qiszero(q2
)) {
scale
= zhighbit(q1
->num
) - zhighbit(q1
->den
) + 1;
epsilon2
= qscale(epsilon
, -scale
);
r
->real
= qcos(q2
, epsilon2
);
r
->imag
= qlegtoleg(r
->real
, epsilon2
, _sinisneg_
);
* Raise one complex number to the power of another one to within the
if (cisreal(c2
) && qisint(c2
->real
))
return cpowi(c1
, c2
->real
);
if (cisone(c1
) || ciszero(c1
))
epsilon2
= qscale(epsilon
, -4L);
tmp1
= cln(c1
, epsilon2
);
tmp1
= cexp(tmp2
, epsilon
);
* Return a trivial hash value for a complex number.
hash
+= qhash(c
->imag
) * 2000029;
* Print a complex number in the current output mode.
if (_outmode_
== MODE_FRAC
) {
if (!qiszero(c
->real
) || qiszero(c
->imag
))
qprintnum(c
->real
, MODE_DEFAULT
);
if (!qiszero(c
->real
) && !qisneg(&qtmp
))
qprintnum(&qtmp
, MODE_DEFAULT
);
* Print a complex number in rational representation.
if (!qiszero(r
) || qiszero(i
))
if (!qiszero(r
) && !qisneg(i
))
zprintval(i
->num
, 0L, 0L);
zprintval(i
->den
, 0L, 0L);