/* * hash_complex - hash a COMPLEX * * given: * type - hash type (see hash.h) * c - the COMPLEX * state - the state to hash or NULL * * returns: * the new state */ HASH * hash_complex(int type, void *c, HASH *state) { COMPLEX *complex = (COMPLEX *)c; /* c as a COMPLEX pointer */ /* * initialize if state is NULL */ if (state == NULL) { state = hash_init(type, NULL); } /* * setup for the COMPLEX hash */ (state->chkpt)(state); state->bytes = FALSE; /* * catch the zero special case */ if (ciszero(complex)) { /* note a zero numeric value and return */ (state->note)(HASH_ZERO(state->base), state); return state; } /* * process the real value if not pure imaginary * * We will ignore the real part if the value is of the form 0+xi. */ if (!qiszero(complex->real)) { state = hash_number(type, complex->real, state); } /* * if the NUMBER is not real, process the imaginary value * * We will ignore the imaginary part of the value is of the form x+0i. */ if (!cisreal(complex)) { /* note the sqrt(-1) */ (state->note)(HASH_COMPLEX(state->base), state); /* hash the imaginary value */ state = hash_number(type, complex->imag, state); } /* * all done */ return state; }
/* * Add two complex numbers. */ COMPLEX * cadd(COMPLEX *c1, COMPLEX *c2) { COMPLEX *r; if (ciszero(c1)) return clink(c2); if (ciszero(c2)) return clink(c1); r = comalloc(); if (!qiszero(c1->real) || !qiszero(c2->real)) { qfree(r->real); r->real = qqadd(c1->real, c2->real); } if (!qiszero(c1->imag) || !qiszero(c2->imag)) { qfree(r->imag); r->imag = qqadd(c1->imag, c2->imag); } return r; }
/* * Multiply two complex numbers. * This saves one multiplication over the obvious algorithm by * trading it for several extra additions, as follows. Let * q1 = (a + b) * (c + d) * q2 = a * c * q3 = b * d * Then (a+bi) * (c+di) = (q2 - q3) + (q1 - q2 - q3)i. */ COMPLEX * cmul(COMPLEX *c1, COMPLEX *c2) { COMPLEX *r; NUMBER *q1, *q2, *q3, *q4; if (ciszero(c1) || ciszero(c2)) return clink(&_czero_); if (cisone(c1)) return clink(c2); if (cisone(c2)) return clink(c1); if (cisreal(c2)) return cmulq(c1, c2->real); if (cisreal(c1)) return cmulq(c2, c1->real); /* * Need to do the full calculation. */ r = comalloc(); q2 = qqadd(c1->real, c1->imag); q3 = qqadd(c2->real, c2->imag); q1 = qmul(q2, q3); qfree(q2); qfree(q3); q2 = qmul(c1->real, c2->real); q3 = qmul(c1->imag, c2->imag); q4 = qqadd(q2, q3); qfree(r->real); r->real = qsub(q2, q3); qfree(r->imag); r->imag = qsub(q1, q4); qfree(q1); qfree(q2); qfree(q3); qfree(q4); return r; }
/* * Scale a complex number by a power of two. */ COMPLEX * cscale(COMPLEX *c, long n) { COMPLEX *r; if (ciszero(c) || (n == 0)) return clink(c); r = comalloc(); qfree(r->real); qfree(r->imag); r->real = qscale(c->real, n); r->imag = qscale(c->imag, n); return r; }
/* * Negate a complex number. */ COMPLEX * cneg(COMPLEX *c) { COMPLEX *r; if (ciszero(c)) return clink(&_czero_); r = comalloc(); if (!qiszero(c->real)) { qfree(r->real); r->real = qneg(c->real); } if (!qiszero(c->imag)) { qfree(r->imag); r->imag = qneg(c->imag); } return r; }
/* * Subtract two complex numbers. */ COMPLEX * csub(COMPLEX *c1, COMPLEX *c2) { COMPLEX *r; if ((c1->real == c2->real) && (c1->imag == c2->imag)) return clink(&_czero_); if (ciszero(c2)) return clink(c1); r = comalloc(); if (!qiszero(c1->real) || !qiszero(c2->real)) { qfree(r->real); r->real = qsub(c1->real, c2->real); } if (!qiszero(c1->imag) || !qiszero(c2->imag)) { qfree(r->imag); r->imag = qsub(c1->imag, c2->imag); } return r; }
/* * Invert a complex number. */ COMPLEX * cinv(COMPLEX *c) { COMPLEX *r; NUMBER *q1, *q2, *den; if (ciszero(c)) { math_error("Inverting zero"); /*NOTREACHED*/ } r = comalloc(); if (cisreal(c)) { qfree(r->real); r->real = qinv(c->real); return r; } if (cisimag(c)) { q1 = qinv(c->imag); qfree(r->imag); r->imag = qneg(q1); qfree(q1); return r; } q1 = qsquare(c->real); q2 = qsquare(c->imag); den = qqadd(q1, q2); qfree(q1); qfree(q2); qfree(r->real); r->real = qqdiv(c->real, den); q1 = qqdiv(c->imag, den); qfree(r->imag); r->imag = qneg(q1); qfree(q1); qfree(den); return r; }
/* * Square a complex number. */ COMPLEX * csquare(COMPLEX *c) { COMPLEX *r; NUMBER *q1, *q2; if (ciszero(c)) return clink(&_czero_); if (cisrunit(c)) return clink(&_cone_); if (cisiunit(c)) return clink(&_cnegone_); r = comalloc(); if (cisreal(c)) { qfree(r->real); r->real = qsquare(c->real); return r; } if (cisimag(c)) { qfree(r->real); q1 = qsquare(c->imag); r->real = qneg(q1); qfree(q1); return r; } q1 = qsquare(c->real); q2 = qsquare(c->imag); qfree(r->real); r->real = qsub(q1, q2); qfree(q1); qfree(q2); qfree(r->imag); q1 = qmul(c->real, c->imag); r->imag = qscale(q1, 1L); qfree(q1); return r; }
/* * Divide two complex numbers. */ COMPLEX * cdiv(COMPLEX *c1, COMPLEX *c2) { COMPLEX *r; NUMBER *q1, *q2, *q3, *den; if (ciszero(c2)) { math_error("Division by zero"); /*NOTREACHED*/ } if ((c1->real == c2->real) && (c1->imag == c2->imag)) return clink(&_cone_); r = comalloc(); if (cisreal(c1) && cisreal(c2)) { qfree(r->real); r->real = qqdiv(c1->real, c2->real); return r; } if (cisimag(c1) && cisimag(c2)) { qfree(r->real); r->real = qqdiv(c1->imag, c2->imag); return r; } if (cisimag(c1) && cisreal(c2)) { qfree(r->imag); r->imag = qqdiv(c1->imag, c2->real); return r; } if (cisreal(c1) && cisimag(c2)) { qfree(r->imag); q1 = qqdiv(c1->real, c2->imag); r->imag = qneg(q1); qfree(q1); return r; } if (cisreal(c2)) { qfree(r->real); qfree(r->imag); r->real = qqdiv(c1->real, c2->real); r->imag = qqdiv(c1->imag, c2->real); return r; } q1 = qsquare(c2->real); q2 = qsquare(c2->imag); den = qqadd(q1, q2); qfree(q1); qfree(q2); q1 = qmul(c1->real, c2->real); q2 = qmul(c1->imag, c2->imag); q3 = qqadd(q1, q2); qfree(q1); qfree(q2); qfree(r->real); r->real = qqdiv(q3, den); qfree(q3); q1 = qmul(c1->real, c2->imag); q2 = qmul(c1->imag, c2->real); q3 = qsub(q2, q1); qfree(q1); qfree(q2); qfree(r->imag); r->imag = qqdiv(q3, den); qfree(q3); qfree(den); return r; }