/* Copyright (C) 2002 Paul Wilkins This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* complex.c by Paul Wilkins */ #include #include #include #include "complex.h" #include "real.h" #include "number.h" #include "constant.h" #include "mode.h" #include "lcd.h" /* we need to know the display size */ /* create a new complex number */ Cmplx * newCmplx(){ Cmplx *p; if(NULL == (p = (Cmplx *)malloc(sizeof(Cmplx)))){ perror("Malloc"); exit(0); } p->re = NULL; p->im = NULL; return p; } void freeCmplx(Cmplx *a){ if(a){ if(a->re) freeReal(a->re); if(a->im) freeReal(a->im); free((char *)a); a = NULL; /* make sure we die... */ } } /* assumes data in in rectangular form */ Cmplx * setCmplxReal(Cmplx *a, Real *rp, Real *ip){ if(a == NULL || rp == NULL || ip == NULL) { fprintf(stderr, "setCmplxReal(NULL)\n"); exit(0); } if(a->re) free((char *)a->re); if(a->im) free((char *)a->im); a->re = setRealReal(newReal(), rp); a->im = setRealReal(newReal(), ip); return a; } /* assumes data in in form defined by getRadixMode() and getPolarMode() */ Cmplx * inputCmplxReal(Cmplx *a, Real *rp, Real *ip){ Cmplx *c1, *c2; if(a == NULL || rp == NULL || ip == NULL) { fprintf(stderr, "setCmplxReal(NULL)\n"); exit(0); } if(a->re) free((char *)a->re); if(a->im) free((char *)a->im); if(getPolarMode() == POLAR){ c1 = newCmplx(); c1->re = setRealReal(newReal(), rp); if(getRadixMode() == DEGREES) c1->im = divReal(ip, real180Pi); else c1->im = setRealReal(newReal(), ip); c2 = rectCmplx(c1); setCmplxCmplx(a, c2); freeCmplx(c1); freeCmplx(c2); } else { a->re = setRealReal(newReal(), rp); a->im = setRealReal(newReal(), ip); } return a; } Cmplx * setCmplxCmplx(Cmplx *a, Cmplx *b){ if(a == NULL || b == NULL) { fprintf(stderr, "setCmplxCmplx(NULL)\n"); exit(0); } if(a->re) free((char *)a->re); if(a->im) free((char *)a->im); a->re = setRealReal(newReal(), b->re); a->im = setRealReal(newReal(), b->im); return a; } #define COMPLEX_PRINT_SIZE 90 char * printCmplxShort(Cmplx *a){ char *c; char *p1; char *p2; Cmplx *c1; if(NULL == (c=(char *)malloc(COMPLEX_PRINT_SIZE))) { perror("Malloc"); exit(0); } if(getPolarMode() == POLAR){ c1 = polarCmplx(a); p1 = printReal(c1->re); if(getRadixMode() == DEGREES){ mulEqReal(c1->im, real180Pi); p2 = printReal(c1->im); } else { p2 = printReal(c1->im); } freeCmplx(c1); } else { p1 = printReal(a->re); p2 = printReal(a->im); } sprintf(c, "(%s, %s)", p1, p2); free(p1); free(p2); return c; } char * printCmplx(Cmplx *a){ char *c; char *p1; char *p2; Cmplx *c1; if(NULL == (c=(char *)malloc(COMPLEX_PRINT_SIZE))) { perror("Malloc"); exit(0); } *c = '\0'; if(getPolarMode() == POLAR){ c1 = polarCmplx(a); p1 = printReal(c1->re); if(getRadixMode() == DEGREES){ mulEqReal(c1->im, real180Pi); p2 = printReal(c1->im); } else { p2 = printReal(c1->im); } freeCmplx(c1); } else { p1 = printReal(a->re); p2 = printReal(a->im); } sprintf(c, "(%s, %s)", p1, p2); if(strlen(p1)+strlen(p2)+4 > lcdWidth-4) *(c+strlen(p1)+2) = '\n'; free(p1); free(p2); return c; } Cmplx * negCmplx(Cmplx *a){ Cmplx *p = newCmplx(); p->re = negReal(a->re); p->im = negReal(a->im); return p; } Cmplx * negEqCmplx(Cmplx *a){ negEqReal(a->re); negEqReal(a->im); return a; } /* calculate 1/(re+im) */ Cmplx * invCmplx(Cmplx *a){ Real *r1, *r2, *r3; Cmplx *p = newCmplx(); /* r1 = re^2 + im^2 */ r1 = mulReal(a->re, a->re); r2 = mulReal(a->im, a->im); addEqReal(r1, r2); p->re = divReal(a->re, r1); r3 = divReal(a->im, r1); p->im = negEqReal(r3); freeReal(r1); freeReal(r2); return p; } /* calculate 1/(re+im) */ Cmplx * invEqCmplx(Cmplx *a){ Real *r1, *r2; /* r1 = re^2 + im^2 */ r1 = mulReal(a->re, a->re); r2 = mulReal(a->im, a->im); addEqReal(r1, r2); divEqReal(a->re, r1); divEqReal(a->im, r1); negEqReal(a->im); freeReal(r1); freeReal(r2); return a; } Cmplx * powCmplxInt(Cmplx *a, int b){ int i; Cmplx *c1, *c2; c1 = setCmplxCmplx(newCmplx(), a);; for(i=1; ire = absCmplx(a); p->im = thetaCmplx(a); return p; } Real * absCmplx(Cmplx *a){ Real *re, *ri; Real *r1, *r2; /* Implements re = re^2 + im^2 but without the range problem */ re = absReal(a->re); ri = absReal(a->im); if(1 == cmpReal(re, ri)){ r2 = re; /* bigger */ r1 = ri; /* smaller */ } else { r2 = ri; r1 = re; } divEqReal(r1, r2); mulEqReal(r1, r1); addEqReal(r1, realOne); powEqReal(r1, realHalf); mulEqReal(r1, r2); freeReal(r2); return r1; } Real * thetaCmplx(Cmplx *a){ int sign_re; Real *r1, *r2; Real *theta; r2 = atanEqReal(divReal(a->im, a->re)); sign_re = cmpReal(a->re, realZero); if(0 == sign_re){ /* -90 deg */ if(-1 == cmpReal(a->im, realZero)) theta = setRealDouble(newReal(), -M_PI/2.0); else /* 90 deg */ theta = setRealDouble(newReal(), M_PI/2.0); freeReal(r2); } /* quadrant 2 and 3 */ else if(-1 == sign_re){ /* quad 3 */ if(-1 == cmpReal(a->im, realZero)) theta = subEqReal(r2, realPi); else /* quad 2 */ theta = addEqReal(r2, realPi); } /* quadrant 1 and 4 */ else{ theta = r2; } return theta; } Cmplx * rectCmplx(Cmplx *a){ Real *r1, *r2; Cmplx *p = newCmplx(); r1 = cosReal(a->im); r2 = sinReal(a->im); p->re = mulEqReal(r1, a->re); p->im = mulEqReal(r2, a->re); return p; } Cmplx * lnCmplx(Cmplx *a){ Cmplx *p; p = polarCmplx(a); lnEqReal(p->re); return p; } /* Note: instead of doing lnCmplx(a)/lnReal(10.0) I did it * like this. Hopefully this way is a little faster??? */ Cmplx * logCmplx(Cmplx *a){ Real *r1; Cmplx *p; p = polarCmplx(a); r1 = lnReal(realTen); logEqReal(p->re); divEqReal(p->im, r1); freeReal(r1); return p; } Cmplx * expCmplx(Cmplx *a){ Real *rr, *ri, *re; Cmplx *p = newCmplx(); rr = cosReal(a->im); ri = sinReal(a->im); re = expReal(a->re); p->re = mulEqReal(rr, re); p->im = mulEqReal(ri, re); freeReal(re); return p; } Cmplx * expEqCmplx(Cmplx *a){ Real *r1, *r2; r1 = expReal(a->re); /* res.re = e^re * cos(im) */ mulEqReal(expEqReal(a->re), (r2=cosReal(a->im))); /* res.im = e^re * sin(im) */ mulEqReal(sinEqReal(a->im), r1); freeReal(r1); freeReal(r2); return a; } /***************** TRIG *************************/ Cmplx * sinCmplx(Cmplx *a){ Real *r1; Cmplx *p; Cmplx *c1, *c2, *c3, *c4, *c5; c1 = mulCmplx(cmplxI, a); c2 = expCmplx(c1); negEqCmplx(c1); c4 = expCmplx(c1); c5 = subCmplx(c2, c4); freeCmplx(c1); freeCmplx(c2); freeCmplx(c4); r1 = setRealDouble(newReal(), 2.0); c1 = setCmplxReal(newCmplx(), realZero, r1); freeReal(r1); p = divCmplx(c5, c1); freeCmplx(c1); freeCmplx(c5); return p; } Cmplx * cosCmplx(Cmplx *a){ Cmplx *p; Cmplx *c1, *c2, *c4; c1 = mulCmplx(cmplxI, a); c2 = expCmplx(c1); negEqCmplx(c1); c4 = expCmplx(c1); p = addCmplx(c2, c4); freeCmplx(c1); freeCmplx(c2); freeCmplx(c4); mulEqReal(p->re, realHalf); mulEqReal(p->im, realHalf); return p; } Cmplx * tanCmplx(Cmplx *a){ Cmplx *p; Cmplx *c1, *c2; c1 = sinCmplx(a); c2 = cosCmplx(a); p = divCmplx(c1, c2); freeCmplx(c1); freeCmplx(c2); return p; } Cmplx * asinCmplx(Cmplx *a){ Real *r1; Cmplx *z, *sqzp1, *sqzm1; Cmplx *c1, *c2, *c3, *c4, *c5, *c6, *c7; z = newCmplx(); setCmplxCmplx(z, a); if(1 == cmpReal(realZero, a->re)) negEqCmplx(z); /* sqrt(z + 1) */ c1 = addCmplxReal(z, realOne); sqzp1 = powCmplxReal(c1, realHalf); freeCmplx(c1); /* sqrt(z - 1) */ c1 = subCmplxReal(z, realOne); sqzm1 = powCmplxReal(c1, realHalf); freeCmplx(c1); /* if imag_part(sqzp1) < 0.0 then sqzp1 = -sqzp1 */ if(1 == cmpReal(realZero, sqzp1->im)) negEqCmplx(sqzp1); c2 = mulCmplx(sqzp1, sqzm1); c3 = addCmplx(c2, z); c4 = lnCmplx(c3); c5 = mulCmplx(c4, cmplxI); c6 = subRealCmplx(realPi2, c5); if(1 == cmpReal(c6->re, realPi2)){ c7 = subRealCmplx(realPi, c6); freeCmplx(c6); c6 = c7; } r1 = negReal(realPi); if(-1 == cmpReal(c6->re, r1)){ c7 = subRealCmplx(r1, c6); freeCmplx(c6); c6 = c7; } freeReal(r1); if(1 == cmpReal(realZero, a->re)) negEqCmplx(c6); freeCmplx(sqzp1); freeCmplx(sqzm1); freeCmplx(z); freeCmplx(c2); freeCmplx(c3); freeCmplx(c4); freeCmplx(c5); return c6; } Cmplx * acosCmplx(Cmplx *a){ Cmplx *p, *c1; c1 = asinCmplx(a); p = subRealCmplx(realPi2, c1); freeCmplx(c1); return p; } Cmplx * atanCmplx(Cmplx *a){ Real *r, *x, *y, *rsq; Real *r1, *r2, *r3, *r4, *r5, *r6, *r7; Cmplx *p = newCmplx(); r = absCmplx(a); x = a->re; y = a->im; rsq = mulReal(r, r); freeReal(r); r1 = mulReal(x, realTwo); r2 = subReal(realOne, rsq); r3 = atan2Real(r1, r2); p->re = mulReal(r3, realHalf); freeReal(r1); freeReal(r2); freeReal(r3); r1 = mulReal(y, realTwo); r2 = addReal(rsq, realOne); r3 = addReal(r2, r1); r4 = subReal(r2, r1); r5 = divReal(r3, r4); r6 = lnReal(r5); r7 = mulReal(realHalf, realHalf); p->im = mulReal(r6, r7); freeReal(r1); freeReal(r2); freeReal(r3); freeReal(r4); freeReal(r5); freeReal(r6); freeReal(r7); freeReal(rsq); return p; } /*************** MULTIPLY **********************/ /* multiply 2 Cmplx numbers */ Cmplx * mulCmplx(Cmplx *a, Cmplx *b){ Real *r1, *r2, *r3, *r4, *r5, *r6; Cmplx *p = newCmplx(); r1 = mulReal(a->re, b->re); r2 = mulReal(a->im, b->im); r3 = mulReal(a->re, b->im); r4 = mulReal(a->im, b->re); p->re = subEqReal(r1, r2); p->im = addEqReal(r3, r4); freeReal(r2); freeReal(r4); return p; } /* multiply a Cmplx by a Real number */ Cmplx * mulCmplxReal(Cmplx *a, Real *b){ Cmplx *p = newCmplx(); p->re = mulReal(a->re, b); p->im = mulReal(a->im, b); return p; } /***************** DIVIDE ***********************/ /* divide 2 Cmplx numbers */ Cmplx * divCmplx(Cmplx *a, Cmplx *b){ Real *r2, *r3; Real *r5, *r6; Real *r8, *r9; Cmplx *p = newCmplx(); /* r3 = bre^2 + bim^2 */ r3 = mulReal(b->re, b->re); r2 = mulReal(b->im, b->im); addEqReal(r3, r2); /* r6 = bre*are + bim*aim */ r6 = mulReal(b->re, a->re); r5 = mulReal(b->im, a->im); addEqReal(r6, r5); /* r9 = bre*aim - bim*are */ r9 = mulReal(b->re, a->im); r8 = mulReal(b->im, a->re); subEqReal(r9, r8); p->re = divEqReal(r6, r3); p->im = divEqReal(r9, r3); freeReal(r2); freeReal(r3); freeReal(r5); freeReal(r8); return p; } /* divide a Cmplx by a Real number */ Cmplx * divCmplxReal(Cmplx *a, Real *b){ Cmplx *p = newCmplx(); p->re = divReal(a->re, b); p->im = divReal(a->im, b); return p; } /* divide a Real by a Cmplx number */ Cmplx * divRealCmplx(Real *a, Cmplx *b){ Real *r2, *r3, *r4, *r5, *r6; Cmplx *p = newCmplx(); /* r3 = bre^2 + bim^2 */ r3 = mulReal(b->re, b->re); r2 = mulReal(b->im, b->im); addEqReal(r3, r2); r4 = divReal(b->re, r3); r5 = divReal(b->im, r3); r6 = negReal(a); p->re = mulEqReal(r4, a); p->im = mulEqReal(r5, r6); freeReal(r2); freeReal(r3); freeReal(r6); return p; } /***************** ADD ***************************/ /* add 2 Cmplx numbers */ Cmplx * addCmplx(Cmplx *a, Cmplx *b){ Cmplx *p = newCmplx(); p->re = addReal(a->re, b->re); p->im = addReal(a->im, b->im); return p; } /* add a Cmplx and a Real number */ Cmplx * addCmplxReal(Cmplx *a, Real *b){ Cmplx *p = newCmplx(); p->re = addReal(a->re, b); p->im = setRealReal(newReal(), a->im); return p; } /******************* SUBTRACT *******************/ /* subtract 2 Cmplx numbers */ Cmplx * subCmplx(Cmplx *a, Cmplx *b){ Cmplx *p = newCmplx(); p->re = subReal(a->re, b->re); p->im = subReal(a->im, b->im); return p; } /* subtract a Real from a Cmplx */ Cmplx * subCmplxReal(Cmplx *a, Real *b){ Cmplx *p = newCmplx(); p->re = subReal(a->re, b); p->im = setRealReal(newReal(), a->im); return p; } /* subtract a Cmplx from a Real */ Cmplx * subRealCmplx(Real *a, Cmplx *b){ Cmplx *p = newCmplx(); p->re = subReal(a, b->re); p->im = negReal(b->im); return p; }