ngspice/src/maths/cmaths/cmath1.c

456 lines
12 KiB
C
Raw Normal View History

2000-04-27 22:03:57 +02:00
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
**********/
/*
* Routines to do complex mathematical functions. These routines require
* the -lm libraries. We sacrifice a lot of space to be able
* to avoid having to do a seperate call for every vector element,
* but it pays off in time savings. These routines should never
* allow FPE's to happen.
*
* Complex functions are called as follows:
* cx_something(data, type, length, &newlength, &newtype),
* and return a char * that is cast to complex or double.
*
*/
#include <ngspice.h>
#include <cpdefs.h>
#include <dvec.h>
2000-04-27 22:03:57 +02:00
#include "cmath1.h"
/* This flag determines whether degrees or radians are used. The radtodeg
* and degtorad macros are no-ops if this is FALSE.
*/
bool cx_degrees = FALSE;
void *
cx_mag(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d = alloc_d(length);
double *dd = (double *) data;
complex *cc = (complex *) data;
int i;
*newlength = length;
*newtype = VF_REAL;
if (type == VF_REAL)
for (i = 0; i < length; i++)
d[i] = FTEcabs(dd[i]);
else
for (i = 0; i < length; i++)
d[i] = cmag(&cc[i]);
return ((void *) d);
}
void *
cx_ph(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d = alloc_d(length);
complex *cc = (complex *) data;
int i;
*newlength = length;
*newtype = VF_REAL;
if (type == VF_COMPLEX)
for (i = 0; i < length; i++) {
d[i] = radtodeg(cph(&cc[i]));
}
/* Otherwise it is 0, but tmalloc zeros the stuff already. */
return ((void *) d);
}
/* If this is pure imaginary we might get real, but never mind... */
void *
cx_j(void *data, short int type, int length, int *newlength, short int *newtype)
{
complex *c = alloc_c(length);
complex *cc = (complex *) data;
double *dd = (double *) data;
int i;
*newlength = length;
*newtype = VF_COMPLEX;
if (type == VF_COMPLEX)
for (i = 0; i < length; i++) {
realpart(&c[i]) = - imagpart(&cc[i]);
imagpart(&c[i]) = realpart(&cc[i]);
}
else
for (i = 0; i < length; i++) {
imagpart(&c[i]) = dd[i];
/* Real part is already 0. */
}
return ((void *) c);
}
void *
cx_real(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d = alloc_d(length);
double *dd = (double *) data;
complex *cc = (complex *) data;
int i;
*newlength = length;
*newtype = VF_REAL;
if (type == VF_COMPLEX)
for (i = 0; i < length; i++)
d[i] = realpart(&cc[i]);
else
for (i = 0; i < length; i++)
d[i] = dd[i];
return ((void *) d);
}
void *
cx_imag(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d = alloc_d(length);
double *dd = (double *) data;
complex *cc = (complex *) data;
int i;
*newlength = length;
*newtype = VF_REAL;
if (type == VF_COMPLEX)
for (i = 0; i < length; i++)
d[i] = imagpart(&cc[i]);
else
for (i = 0; i < length; i++)
d[i] = dd[i];
return ((void *) d);
}
/* This is obsolete... */
void *
cx_pos(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d = alloc_d(length);
double *dd = (double *) data;
complex *cc = (complex *) data;
int i;
*newlength = length;
*newtype = VF_REAL;
if (type == VF_COMPLEX)
for (i = 0; i < length; i++)
d[i] = ((realpart(&cc[i]) > 0.0) ? 1.0 : 0.0);
else
for (i = 0; i < length; i++)
d[i] = ((dd[i] > 0.0) ? 1.0 : 0.0);
return ((void *) d);
}
void *
cx_db(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d = alloc_d(length);
double *dd = (double *) data;
complex *cc = (complex *) data;
double tt;
int i;
*newlength = length;
*newtype = VF_REAL;
if (type == VF_COMPLEX)
for (i = 0; i < length; i++) {
tt = cmag(&cc[i]);
rcheck(tt > 0, "db");
/*
if (tt == 0.0)
d[i] = 20.0 * - log(HUGE);
else
*/
d[i] = 20.0 * log10(tt);
}
else
for (i = 0; i < length; i++) {
rcheck(dd[i] > 0, "db");
/*
if (dd[i] == 0.0)
d[i] = 20.0 * - log(HUGE);
else
*/
d[i] = 20.0 * log10(dd[i]);
}
return ((void *) d);
}
void *
cx_log(void *data, short int type, int length, int *newlength, short int *newtype)
{
*newlength = length;
if (type == VF_COMPLEX) {
complex *c;
complex *cc = (complex *) data;
int i;
c = alloc_c(length);
*newtype = VF_COMPLEX;
for (i = 0; i < length; i++) {
double td;
td = cmag(&cc[i]);
/* Perhaps we should trap when td = 0.0, but Ken wants
* this to be possible...
*/
rcheck(td >= 0, "log");
if (td == 0.0) {
realpart(&c[i]) = - log10(HUGE);
imagpart(&c[i]) = 0.0;
} else {
realpart(&c[i]) = log10(td);
imagpart(&c[i]) = atan2(imagpart(&cc[i]),
realpart(&cc[i]));
}
}
return ((void *) c);
} else {
double *d;
double *dd = (double *) data;
int i;
d = alloc_d(length);
*newtype = VF_REAL;
for (i = 0; i < length; i++) {
rcheck(dd[i] >= 0, "log");
if (dd[i] == 0.0)
d[i] = - log10(HUGE);
else
d[i] = log10(dd[i]);
}
return ((void *) d);
}
}
void *
cx_ln(void *data, short int type, int length, int *newlength, short int *newtype)
{
*newlength = length;
if (type == VF_COMPLEX) {
complex *c;
complex *cc = (complex *) data;
int i;
c = alloc_c(length);
*newtype = VF_COMPLEX;
for (i = 0; i < length; i++) {
double td;
td = cmag(&cc[i]);
rcheck(td >= 0, "ln");
if (td == 0.0) {
realpart(&c[i]) = - log(HUGE);
imagpart(&c[i]) = 0.0;
} else {
realpart(&c[i]) = log(td);
imagpart(&c[i]) = atan2(imagpart(&cc[i]),
realpart(&cc[i]));
}
}
return ((void *) c);
} else {
double *d;
double *dd = (double *) data;
int i;
d = alloc_d(length);
*newtype = VF_REAL;
for (i = 0; i < length; i++) {
rcheck(dd[i] >= 0, "ln");
if (dd[i] == 0.0)
d[i] = - log(HUGE);
else
d[i] = log(dd[i]);
}
return ((void *) d);
}
}
void *
cx_exp(void *data, short int type, int length, int *newlength, short int *newtype)
{
*newlength = length;
if (type == VF_COMPLEX) {
complex *c;
complex *cc = (complex *) data;
int i;
c = alloc_c(length);
*newtype = VF_COMPLEX;
for (i = 0; i < length; i++) {
double td;
td = exp(realpart(&cc[i]));
realpart(&c[i]) = td * cos(imagpart(&cc[i]));
imagpart(&c[i]) = td * sin(imagpart(&cc[i]));
}
return ((void *) c);
} else {
double *d;
double *dd = (double *) data;
int i;
d = alloc_d(length);
*newtype = VF_REAL;
for (i = 0; i < length; i++)
d[i] = exp(dd[i]);
return ((void *) d);
}
}
void *
cx_sqrt(void *data, short int type, int length, int *newlength, short int *newtype)
{
double *d;
complex *c;
double *dd = (double *) data;
complex *cc = (complex *) data;
int i, cres = (type == VF_REAL) ? 0 : 1;
if (type == VF_REAL)
for (i = 0; i < length; i++)
if (dd[i] < 0.0)
cres = 1;
if (cres) {
c = alloc_c(length);
*newtype = VF_COMPLEX;
} else {
d = alloc_d(length);
*newtype = VF_REAL;
}
*newlength = length;
if (type == VF_COMPLEX) {
for (i = 0; i < length; i++) {
if (realpart(&cc[i]) == 0.0) {
if (imagpart(&cc[i]) == 0.0) {
realpart(&c[i]) = 0.0;
imagpart(&c[i]) = 0.0;
} else if (imagpart(&cc[i]) > 0.0) {
realpart(&c[i]) = sqrt (0.5 *
imagpart(&cc[i]));
imagpart(&c[i]) = realpart(&c[i]);
} else {
imagpart(&c[i]) = sqrt( -0.5 *
imagpart(&cc[i]));
realpart(&c[i]) = - imagpart(&c[i]);
}
} else if (realpart(&cc[i]) > 0.0) {
if (imagpart(&cc[i]) == 0.0) {
realpart(&c[i]) =
sqrt(realpart(&cc[i]));
imagpart(&c[i]) = 0.0;
} else if (imagpart(&cc[i]) < 0.0) {
realpart(&c[i]) = -sqrt(0.5 *
(cmag(&cc[i]) + realpart(&cc[i])));
} else {
realpart(&c[i]) = sqrt(0.5 *
(cmag(&cc[i]) + realpart(&cc[i])));
}
imagpart(&c[i]) = imagpart(&cc[i]) / (2.0 *
realpart(&c[i]));
} else { /* realpart(&cc[i]) < 0.0) */
if (imagpart(&cc[i]) == 0.0) {
realpart(&c[i]) = 0.0;
imagpart(&c[i]) =
sqrt(- realpart(&cc[i]));
} else {
if (imagpart(&cc[i]) < 0.0)
imagpart(&c[i]) = - sqrt(0.5 *
(cmag(&cc[i]) -
realpart(&cc[i])));
else
imagpart(&c[i]) = sqrt(0.5 *
(cmag(&cc[i]) -
realpart(&cc[i])));
realpart(&c[i]) = imagpart(&cc[i]) /
(2.0 * imagpart(&c[i]));
}
}
}
return ((void *) c);
} else if (cres) {
for (i = 0; i < length; i++)
if (dd[i] < 0.0)
imagpart(&c[i]) = sqrt(- dd[i]);
else
realpart(&c[i]) = sqrt(dd[i]);
return ((void *) c);
} else {
for (i = 0; i < length; i++)
d[i] = sqrt(dd[i]);
return ((void *) d);
}
}
void *
cx_sin(void *data, short int type, int length, int *newlength, short int *newtype)
{
*newlength = length;
if (type == VF_COMPLEX) {
complex *c;
complex *cc = (complex *) data;
int i;
c = alloc_c(length);
*newtype = VF_COMPLEX;
for (i = 0; i < length; i++) {
realpart(&c[i]) = sin(degtorad(realpart(&cc[i]))) *
cosh(degtorad(imagpart(&cc[i])));
imagpart(&c[i]) = cos(degtorad(realpart(&cc[i]))) *
sinh(degtorad(imagpart(&cc[i])));
}
return ((void *) c);
} else {
double *d;
double *dd = (double *) data;
int i;
d = alloc_d(length);
*newtype = VF_REAL;
for (i = 0; i < length; i++)
d[i] = sin(degtorad(dd[i]));
return ((void *) d);
}
}
void *
cx_cos(void *data, short int type, int length, int *newlength, short int *newtype)
{
*newlength = length;
if (type == VF_COMPLEX) {
complex *c;
complex *cc = (complex *) data;
int i;
c = alloc_c(length);
*newtype = VF_COMPLEX;
for (i = 0; i < length; i++) {
realpart(&c[i]) = cos(degtorad(realpart(&cc[i]))) *
cosh(degtorad(imagpart(&cc[i])));
imagpart(&c[i]) = - sin(degtorad(realpart(&cc[i]))) *
sinh(degtorad(imagpart(&cc[i])));
}
return ((void *) c);
} else {
double *d;
double *dd = (double *) data;
int i;
d = alloc_d(length);
*newtype = VF_REAL;
for (i = 0; i < length; i++)
d[i] = cos(degtorad(dd[i]));
return ((void *) d);
}
}