2 * commath - extended precision complex arithmetic primitive routines
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.1 $
21 * @(#) $Id: commath.c,v 30.1 2007/03/16 11:09:46 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/commath.c,v $
24 * Under source code control: 1990/02/15 01:48:10
25 * File existed as early as: before 1990
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
34 COMPLEX _czero_
= { &_qzero_
, &_qzero_
, 1 };
35 COMPLEX _cone_
= { &_qone_
, &_qzero_
, 1 };
36 COMPLEX _conei_
= { &_qzero_
, &_qone_
, 1 };
38 STATIC COMPLEX _cnegone_
= { &_qnegone_
, &_qzero_
, 1 };
42 * Add two complex numbers.
45 c_add(COMPLEX
*c1
, COMPLEX
*c2
)
54 if (!qiszero(c1
->real
) || !qiszero(c2
->real
)) {
56 r
->real
= qqadd(c1
->real
, c2
->real
);
58 if (!qiszero(c1
->imag
) || !qiszero(c2
->imag
)) {
60 r
->imag
= qqadd(c1
->imag
, c2
->imag
);
67 * Subtract two complex numbers.
70 c_sub(COMPLEX
*c1
, COMPLEX
*c2
)
74 if ((c1
->real
== c2
->real
) && (c1
->imag
== c2
->imag
))
75 return clink(&_czero_
);
79 if (!qiszero(c1
->real
) || !qiszero(c2
->real
)) {
81 r
->real
= qsub(c1
->real
, c2
->real
);
83 if (!qiszero(c1
->imag
) || !qiszero(c2
->imag
)) {
85 r
->imag
= qsub(c1
->imag
, c2
->imag
);
92 * Multiply two complex numbers.
93 * This saves one multiplication over the obvious algorithm by
94 * trading it for several extra additions, as follows. Let
95 * q1 = (a + b) * (c + d)
98 * Then (a+bi) * (c+di) = (q2 - q3) + (q1 - q2 - q3)i.
101 c_mul(COMPLEX
*c1
, COMPLEX
*c2
)
104 NUMBER
*q1
, *q2
, *q3
, *q4
;
106 if (ciszero(c1
) || ciszero(c2
))
107 return clink(&_czero_
);
113 return c_mulq(c1
, c2
->real
);
115 return c_mulq(c2
, c1
->real
);
117 * Need to do the full calculation.
120 q2
= qqadd(c1
->real
, c1
->imag
);
121 q3
= qqadd(c2
->real
, c2
->imag
);
125 q2
= qmul(c1
->real
, c2
->real
);
126 q3
= qmul(c1
->imag
, c2
->imag
);
129 r
->real
= qsub(q2
, q3
);
131 r
->imag
= qsub(q1
, q4
);
141 * Square a complex number.
150 return clink(&_czero_
);
152 return clink(&_cone_
);
154 return clink(&_cnegone_
);
158 r
->real
= qsquare(c
->real
);
163 q1
= qsquare(c
->imag
);
168 q1
= qsquare(c
->real
);
169 q2
= qsquare(c
->imag
);
171 r
->real
= qsub(q1
, q2
);
175 q1
= qmul(c
->real
, c
->imag
);
176 r
->imag
= qscale(q1
, 1L);
183 * Divide two complex numbers.
186 c_div(COMPLEX
*c1
, COMPLEX
*c2
)
189 NUMBER
*q1
, *q2
, *q3
, *den
;
192 math_error("Division by zero");
195 if ((c1
->real
== c2
->real
) && (c1
->imag
== c2
->imag
))
196 return clink(&_cone_
);
198 if (cisreal(c1
) && cisreal(c2
)) {
200 r
->real
= qqdiv(c1
->real
, c2
->real
);
203 if (cisimag(c1
) && cisimag(c2
)) {
205 r
->real
= qqdiv(c1
->imag
, c2
->imag
);
208 if (cisimag(c1
) && cisreal(c2
)) {
210 r
->imag
= qqdiv(c1
->imag
, c2
->real
);
213 if (cisreal(c1
) && cisimag(c2
)) {
215 q1
= qqdiv(c1
->real
, c2
->imag
);
223 r
->real
= qqdiv(c1
->real
, c2
->real
);
224 r
->imag
= qqdiv(c1
->imag
, c2
->real
);
227 q1
= qsquare(c2
->real
);
228 q2
= qsquare(c2
->imag
);
232 q1
= qmul(c1
->real
, c2
->real
);
233 q2
= qmul(c1
->imag
, c2
->imag
);
238 r
->real
= qqdiv(q3
, den
);
240 q1
= qmul(c1
->real
, c2
->imag
);
241 q2
= qmul(c1
->imag
, c2
->real
);
246 r
->imag
= qqdiv(q3
, den
);
254 * Invert a complex number.
260 NUMBER
*q1
, *q2
, *den
;
263 math_error("Inverting zero");
269 r
->real
= qinv(c
->real
);
279 q1
= qsquare(c
->real
);
280 q2
= qsquare(c
->imag
);
285 r
->real
= qqdiv(c
->real
, den
);
286 q1
= qqdiv(c
->imag
, den
);
296 * Negate a complex number.
304 return clink(&_czero_
);
306 if (!qiszero(c
->real
)) {
308 r
->real
= qneg(c
->real
);
310 if (!qiszero(c
->imag
)) {
312 r
->imag
= qneg(c
->imag
);
319 * Take the integer part of a complex number.
320 * This means take the integer part of both components.
331 r
->real
= qint(c
->real
);
333 r
->imag
= qint(c
->imag
);
339 * Take the fractional part of a complex number.
340 * This means take the fractional part of both components.
348 return clink(&_czero_
);
351 r
->real
= qfrac(c
->real
);
353 r
->imag
= qfrac(c
->imag
);
359 * Take the conjugate of a complex number.
360 * This negates the complex part.
370 if (!qiszero(c
->real
)) {
372 r
->real
= qlink(c
->real
);
375 r
->imag
= qneg(c
->imag
);
381 * Return the real part of a complex number.
391 if (!qiszero(c
->real
)) {
393 r
->real
= qlink(c
->real
);
400 * Return the imaginary part of a complex number as a real.
408 return clink(&_czero_
);
411 r
->real
= qlink(c
->imag
);
417 * Add a real number to a complex number.
420 c_addq(COMPLEX
*c
, NUMBER
*q
)
429 r
->real
= qqadd(c
->real
, q
);
430 r
->imag
= qlink(c
->imag
);
436 * Subtract a real number from a complex number.
439 c_subq(COMPLEX
*c
, NUMBER
*q
)
448 r
->real
= qsub(c
->real
, q
);
449 r
->imag
= qlink(c
->imag
);
455 * Shift the components of a complex number left by the specified
456 * number of bits. Negative values shift to the right.
459 c_shift(COMPLEX
*c
, long n
)
463 if (ciszero(c
) || (n
== 0))
468 r
->real
= qshift(c
->real
, n
);
469 r
->imag
= qshift(c
->imag
, n
);
475 * Scale a complex number by a power of two.
478 c_scale(COMPLEX
*c
, long n
)
482 if (ciszero(c
) || (n
== 0))
487 r
->real
= qscale(c
->real
, n
);
488 r
->imag
= qscale(c
->imag
, n
);
494 * Multiply a complex number by a real number.
497 c_mulq(COMPLEX
*c
, NUMBER
*q
)
502 return clink(&_czero_
);
510 r
->real
= qmul(c
->real
, q
);
511 r
->imag
= qmul(c
->imag
, q
);
517 * Divide a complex number by a real number.
520 c_divq(COMPLEX
*c
, NUMBER
*q
)
525 math_error("Division by zero");
535 r
->real
= qqdiv(c
->real
, q
);
536 r
->imag
= qqdiv(c
->imag
, q
);
544 * Construct a complex number given the real and imaginary components.
547 qqtoc(NUMBER
*q1
, NUMBER
*q2
)
551 if (qiszero(q1
) && qiszero(q2
))
552 return clink(&_czero_
);
563 * Compare two complex numbers for equality, returning FALSE if they are equal,
564 * and TRUE if they differ.
567 c_cmp(COMPLEX
*c1
, COMPLEX
*c2
)
571 i
= qcmp(c1
->real
, c2
->real
);
573 i
= qcmp(c1
->imag
, c2
->imag
);
579 * Compare two complex numbers and return a complex number with real and
580 * imaginary parts -1, 0 or 1 indicating relative values of the real and
581 * imaginary parts of the two numbers.
584 c_rel(COMPLEX
*c1
, COMPLEX
*c2
)
591 c
->real
= itoq((long) qrel(c1
->real
, c2
->real
));
592 c
->imag
= itoq((long) qrel(c1
->imag
, c2
->imag
));
599 * Allocate a new complex number.
606 r
= (COMPLEX
*) malloc(sizeof(COMPLEX
));
608 math_error("Cannot allocate complex number");
612 r
->real
= qlink(&_qzero_
);
613 r
->imag
= qlink(&_qzero_
);
619 * Free a complex number.
624 if (--(c
->links
) > 0)