Jspice3
nipzmeth.c File Reference
#include "spice.h"
#include <stdio.h>
#include <math.h>
#include "cktdefs.h"
#include "pzdefs.h"
#include "util.h"
#include "sperror.h"
#include "niext.h"
Include dependency graph for nipzmeth.c:

Go to the source code of this file.

Macros

#define DEBUG(N)   if (0)
 

Functions

 NIpzSym (set,*new)
 
 NIpzComplex (set,*new)
 
 NIpzMuller (set,*newtry)
 
 NIpzSym2 (set,*new)
 

Variables

 CKTpzTrapped
 
double NIpzK
 
int NIpzK_mag
 

Macro Definition Documentation

#define DEBUG (   N)    if (0)

Definition at line 14 of file nipzmeth.c.

Function Documentation

NIpzComplex ( set  ,
new 
)

Definition at line 68 of file nipzmeth.c.

70 {
71  return NIpzSym2(set, new);
72 #ifdef notdef
73  NIpzMuller(set, new);
74 #endif
75 }
NIpzSym2(set,*new)
Definition: nipzmeth.c:229
NIpzMuller(set,*newtry)
Definition: nipzmeth.c:78
NIpzMuller ( set  ,
newtry 
)

Definition at line 78 of file nipzmeth.c.

80 {
81  SPcomplex A, B, C, D, E;
82  SPcomplex h0, h1;
83  SPcomplex j0, j1;
84  SPcomplex lambda_i, delta_i, ds;
85  double scale[3];
86  double q;
87  int mag[3], magx, min;
88  int i, j, error, total;
89 
90  min = -999999;
91  j = 0;
92  total = 0;
93  for (i = 0; i < 3; i++) {
94  if (set[i]->f_def.real != 0.0 || set[i]->f_def.imag != 0.0) {
95  if (min < set[i]->mag_def - 50)
96  min = set[i]->mag_def - 50;
97  total += set[i]->mag_def;
98  j += 1;
99  }
100  }
101 
102  magx = total / j;
103  if (magx < min)
104  magx = min;
105 
106  DEBUG(2) fprintf(stderr, "Base scale: %d / %d (0: %d, 1: %d, 2: %d)\n",
107  magx, min, set[0]->mag_def, set[1]->mag_def, set[2]->mag_def);
108 
109  for (i = 0; i < 3; i++) {
110  mag[i] = set[i]->mag_def - magx;
111  scale[i] = 1.0;
112  while (mag[i] > 0) {
113  scale[i] *= 2.0;
114  mag[i] -= 1;
115  }
116  if (mag[i] < -90)
117  scale[i] = 0.0;
118  else {
119  while (mag[i] < 0) {
120  scale[i] /= 2.0;
121  mag[i] += 1;
122  }
123  }
124  }
125 
126  C_SUBEQ(h0,set[0]->s,set[1]->s);
127  C_SUBEQ(h1,set[1]->s,set[2]->s);
128  C_DIVEQ(lambda_i,h0,h1);
129 
130  /* Quadratic interpolation (Muller's method) */
131 
132  C_EQ(delta_i,lambda_i);
133  delta_i.real += 1.0;
134 
135  /* Quadratic coefficients A, B, C (Note: reciprocal form of eqn) */
136 
137  /* A = lambda_i * (f[i-2] * lambda_i - f[i-1] * delta_i + f[i]) */
138  C_MULEQ(A,scale[2] * set[2]->f_def,lambda_i);
139  C_MULEQ(C,scale[1] * set[1]->f_def,delta_i);
140  C_SUB(A,C);
141  C_ADD(A,scale[0] * set[0]->f_def);
142  C_MUL(A,lambda_i);
143 
144  /* B = f[i-2] * lambda_i * lambda_1 - f[i-1] * delta_i * delta_i
145  + f[i] * (lambda_i + delta_i) */
146  C_MULEQ(B,lambda_i,lambda_i);
147  C_MUL(B,scale[2] * set[2]->f_def);
148  C_MULEQ(C,delta_i,delta_i);
149  C_MUL(C,scale[1] * set[1]->f_def);
150  C_SUB(B,C);
151  C_ADDEQ(C,lambda_i,delta_i);
152  C_MUL(C,scale[0] * set[0]->f_def);
153  C_ADD(B,C);
154 
155  /* C = delta_i * f[i] */
156  C_MULEQ(C,delta_i,scale[0] * set[0]->f_def);
157 
158  while (FABS(A.real) > 1.0 || FABS(A.imag) > 1.0
159  || FABS(B.real) > 1.0 || FABS(B.imag) > 1.0
160  || FABS(C.real) > 1.0 || FABS(C.imag) > 1.0) {
161  A.real /= 2.0;
162  B.real /= 2.0;
163  C.real /= 2.0;
164  A.imag /= 2.0;
165  B.imag /= 2.0;
166  C.imag /= 2.0;
167  }
168 
169  /* discriminate = B * B - 4 * A * C */
170  C_MULEQ(D,B,B);
171  C_MULEQ(E,4.0 * A,C);
172  C_SUB(D,E);
173 
174  DEBUG(2) fprintf(stderr, " Discr: (%g,%g)\n",D.real, D.imag);
175  C_SQRT(D);
176  DEBUG(1) fprintf(stderr, " sqrtDiscr: (%g,%g)\n",D.real, D.imag);
177 
178 #ifndef notdef
179  /* Maximize denominator */
180 
181  DEBUG(1) fprintf(stderr, " B: (%g,%g)\n",B.real, B.imag);
182  /* Dot product */
183  q = B.real * D.real + B.imag * D.imag;
184  if (q > 0.0) {
185  DEBUG(1) fprintf(stderr, " add\n");
186  C_ADD(B,D);
187  } else {
188  DEBUG(1) fprintf(stderr, " sub\n");
189  C_SUB(B,D);
190  }
191 
192 #else
193  /* For trapped zeros, the step should always be positive */
194  if (C.real >= 0.0) {
195  if (B.real < D.real) {
196  C_SUB(B,D);
197  } else {
198  C_ADD(B,D);
199  }
200  } else {
201  if (B.real > D.real) {
202  C_SUB(B,D);
203  } else {
204  C_ADD(B,D);
205  }
206  }
207 #endif
208 
209  DEBUG(1) fprintf(stderr, " C: (%g,%g)\n", C.real, C.imag);
210  C_DIV(C,-0.5 * B);
211 
212  newtry->next = NULL;
213 
214  DEBUG(1) fprintf(stderr, " lambda: (%g,%g)\n",C.real, C.imag);
215  C_MULEQ(newtry->s,h0,C);
216 
217  DEBUG(1) fprintf(stderr, " h: (%g,%g)\n", newtry->s.real, newtry->s.imag);
218 
219  C_ADD(newtry->s,set[0]->s);
220 
221  DEBUG(1) fprintf(stderr, "New try: (%g,%g)\n",
222  newtry->s.real, newtry->s.imag);
223 
224  return OK;
225 
226 }
#define C_MULEQ(A, B, C)
Definition: complex.h:164
#define C_SQRT(A)
Definition: complex.h:98
Definition: cddefs.h:119
if(TDesc==NULL)
Definition: cd.c:1326
#define C_ADD(A, B)
Definition: complex.h:188
#define C_ADDEQ(A, B, C)
Definition: complex.h:193
#define C_EQ(A, B)
Definition: complex.h:132
#define C_SUB(A, B)
Definition: complex.h:198
double real
Definition: complex.h:13
#define C_DIV(A, B)
Definition: complex.h:169
#define C_MUL(A, B)
Definition: complex.h:156
#define OK
Definition: iferrmsg.h:17
Definition: cddefs.h:237
#define NULL
Definition: spdefs.h:121
#define FABS(a)
Definition: util.h:41
return(True)
double imag
Definition: complex.h:14
#define C_DIVEQ(A, B, C)
Definition: complex.h:179
Definition: cddefs.h:227
#define E
Definition: parse.c:443
#define C_SUBEQ(A, B, C)
Definition: complex.h:203
#define DEBUG(N)
Definition: nipzmeth.c:14
NIpzSym ( set  ,
new 
)

Definition at line 23 of file nipzmeth.c.

25 {
26 #ifndef notdef
27  return NIpzSym2(set, new);
28 #else
29  double a, b, c, x0, x1;
30  double dx0, dx1;
31  int a_mag, b_mag, c_mag;
32 
33  dx0 = set[1]->s.real - set[0]->s.real;
34  dx1 = set[2]->s.real - set[1]->s.real;
35 
36  zaddeq(&a, &a_mag, set[1]->f_def.real, set[1]->mag_def,
37  -set[0]->f_def.real, set[0]->mag_def);
38  a /= dx0;
39  zaddeq(&b, &b_mag, set[2]->f_def.real, set[2]->mag_def,
40  -set[1]->f_def.real, set[1]->mag_def);
41  b /= dx1;
42  zaddeq(&c, &c_mag, b, b_mag, -a, a_mag);
43 
44  /* XXX What if c == 0.0 ? */
45 
46  x0 = (set[0]->s.real + set[1]->s.real) / 2.0;
47  x1 = (set[1]->s.real + set[2]->s.real) / 2.0;
48 
49  c /= (x1 - x0);
50 
51  new->s.real = - a / c;
52  c_mag -= a_mag;
53 
54  new->s.imag = 0.0;
55 
56  while (c_mag > 0) {
57  new->s.real /= 2.0;
58  c_mag -= 1;
59  }
60  while (c_mag < 0) {
61  new->s.real *= 2.0;
62  c_mag += 1;
63  }
64  new->s.real += set[0]->s.real;
65 #endif
66 }
NIpzSym2(set,*new)
Definition: nipzmeth.c:229
void zaddeq()
Definition: sced.h:120
static double c
Definition: vectors.c:16
NIpzSym2 ( set  ,
new 
)

Definition at line 229 of file nipzmeth.c.

231 {
232  double a, b, c, x0, x1;
233  double dx0, dx1, d2x, diff;
234  double disc;
235  int a_mag, b_mag, c_mag;
236  int tmag;
237  int error;
238  int disc_mag;
239  int new_mag;
240 
241  error = OK;
242 
243  /*
244  NIpzK = 0.0;
245  NIpzK_mag = 0;
246  */
247 
248  /* Solve for X = the distance from set[1], where X > 0 => root < set[1] */
249  dx0 = set[1]->s.real - set[0]->s.real;
250  dx1 = set[2]->s.real - set[1]->s.real;
251 
252  x0 = (set[0]->s.real + set[1]->s.real) / 2.0;
253  x1 = (set[1]->s.real + set[2]->s.real) / 2.0;
254  /* d2x = x1 - x0; */
255  d2x = (set[2]->s.real - set[0]->s.real) / 2.0;
256 
257  zaddeq(&a, &a_mag, set[1]->f_def.real, set[1]->mag_def,
258  -set[0]->f_def.real, set[0]->mag_def);
259 
260  tmag = 0;
261  R_NORM(dx0,tmag);
262  a /= dx0;
263  a_mag -= tmag;
264  R_NORM(a,a_mag);
265 
266  zaddeq(&b, &b_mag, set[2]->f_def.real, set[2]->mag_def,
267  -set[1]->f_def.real, set[1]->mag_def);
268 
269  tmag = 0;
270  R_NORM(dx1,tmag);
271  b /= dx1;
272  b_mag -= tmag;
273  R_NORM(b,b_mag);
274 
275  zaddeq(&c, &c_mag, b, b_mag, -a, a_mag);
276 
277  tmag = 0;
278  R_NORM(d2x,tmag);
279  c /= d2x; /* = f'' */
280  c_mag -= tmag;
281  R_NORM(c,c_mag);
282 
283  if (c == 0.0 || (a == 0.0 || c_mag < a_mag - 40)
284  && (b = 0.0 ||c_mag < b_mag - 40)) {
285  /*fprintf(stderr, "\t- linear (%g, %d)\n", c, c_mag);*/
286  if (a == 0.0) {
287  a = b;
288  a_mag = b_mag;
289  }
290  if (a != 0.0) {
291  new->s.real = - set[1]->f_def.real / a;
292  a_mag -= set[1]->mag_def;
293  while (a_mag > 0) {
294  new->s.real /= 2.0;
295  a_mag -= 1;
296  }
297  while (a_mag < 0) {
298  new->s.real *= 2.0;
299  a_mag += 1;
300  }
301  new->s.real += set[1]->s.real;
302  } else
303  new->s.real = set[1]->s.real;
304  } else {
305 
306  /* Quadratic power series about set[1]->s.real */
307  /* c : d2f/dx2 @ s1 (assumed constant for all s), or "2A" */
308 
309  /* a : (df/dx) / (d2f/dx2) @ s1, or "B/2A" */
310  a /= c;
311  R_NORM(a,a_mag);
312  a_mag -= c_mag;
313 
314  diff = set[1]->s.real - x0;
315  tmag = 0;
316  R_NORM(diff,tmag);
317 
318  zaddeq(&a, &a_mag, a, a_mag, diff, tmag);
319 
320  /* b : f(s1) / (1/2 d2f/ds2), or "C / A" */
321  b = 2.0 * set[1]->f_def.real / c;
322  b_mag = set[1]->mag_def - c_mag;
323  R_NORM(b,b_mag);
324 
325  disc = a * a;
326  disc_mag = 2 * a_mag;
327 
328  /* disc = a^2 - b :: (B/2A)^2 - C/A */
329  zaddeq(&disc, &disc_mag, disc, disc_mag, - b, b_mag);
330 
331  if (disc < 0.0) {
332  /* Look for minima instead, but save radical for later work */
333  disc *= -1;
334  new_mag = 1;
335  }
336 
337  if (disc_mag % 2 == 0)
338  disc = sqrt(disc);
339  else {
340  disc = sqrt(2.0 * disc);
341  disc_mag -= 1;
342  }
343  disc_mag /= 2;
344 
345  if (new_mag != 0) {
346  if (NIpzK == 0.0) {
347  NIpzK = disc;
348  NIpzK_mag = disc_mag;
349  DEBUG(1) fprintf(stderr, "New NIpzK: %g*2^%d\n",
350  NIpzK, NIpzK_mag);
351  } else {
352  DEBUG(1) fprintf(stderr,
353  "Ignore NIpzK: %g*2^%d for previous value of %g*2^%d\n",
354  disc, disc_mag,
355  NIpzK, NIpzK_mag);
356  }
357  disc = 0.0;
358  disc_mag = 0;
359  }
360 
361  /* NOTE: c & b get reused here-after */
362 
363  if (a * disc >= 0.0) {
364  zaddeq(&c, &c_mag, a, a_mag, disc, disc_mag);
365  } else {
366  zaddeq(&c, &c_mag, a, a_mag, -disc, disc_mag);
367  }
368 
369  /* second root = C / (first root) */
370  if (c != 0.0) {
371  b /= c;
372  b_mag -= c_mag;
373  } else {
374  /* special case */
375  b = 0.0;
376  b = 0;
377  }
378 
379  zaddeq(&b, &b_mag, set[1]->s.real, 0, -b, b_mag);
380  zaddeq(&c, &c_mag, set[1]->s.real, 0, -c, c_mag);
381 
382  while (b_mag > 0) {
383  b *= 2.0;
384  b_mag -= 1;
385  }
386  while (b_mag < 0) {
387  b /= 2.0;
388  b_mag += 1;
389  }
390 
391  while (c_mag > 0) {
392  c *= 2.0;
393  c_mag -= 1;
394  }
395  while (c_mag < 0) {
396  c /= 2.0;
397  c_mag += 1;
398  }
399 
400  DEBUG(1) fprintf(stderr, "@@@ (%.15g) -vs- (%.15g)\n", b, c);
401  /* XXXX */
402  if (b < set[0]->s.real || b > set[2]->s.real) {
403  /* b not in range */
404  if (c < set[0]->s.real || c > set[2]->s.real) {
405  DEBUG(1) fprintf(stderr, "@@@ both are junk\n");
406  if (CKTpzTrapped == 1)
407  new->s.real = (set[0]->s.real + set[1]->s.real) / 2.0;
408  else if (CKTpzTrapped == 2)
409  new->s.real = (set[1]->s.real + set[2]->s.real) / 2.0;
410  else if (CKTpzTrapped == 3) {
411  if (FABS(set[1]->s.real - c) < FABS(set[1]->s.real - b)) {
412  DEBUG(1) fprintf(stderr, "@@@ mix w/second (c)\n");
413  new->s.real = (set[1]->s.real + c) / 2.0;
414  } else {
415  DEBUG(1) fprintf(stderr, "@@@ mix w/first (b)\n");
416  new->s.real = (set[1]->s.real + b) / 2.0;
417  }
418  } else
419  ERROR(E_PANIC,"Lost numerical stability");
420  } else {
421  DEBUG(1) fprintf(stderr, "@@@ take second (c)\n");
422  new->s.real = c;
423  }
424  } else {
425  /* b in range */
426  if (c < set[0]->s.real || c > set[2]->s.real) {
427  DEBUG(1) fprintf(stderr, "@@@ take first (b)\n");
428  new->s.real = b;
429  } else {
430  /* Both in range -- take the smallest mag */
431  if (a > 0.0) {
432  DEBUG(1) fprintf(stderr, "@@@ push -- first (b)\n");
433  new->s.real = b;
434  } else {
435  DEBUG(1) fprintf(stderr, "@@@ push -- first (b)\n");
436  new->s.real = c;
437  }
438  }
439  }
440 
441  }
442 
443  new->s.imag = 0.0;
444 
445  return error;
446 }
#define R_NORM(A, B)
Definition: util.h:78
#define E_PANIC
Definition: iferrmsg.h:19
Definition: cddefs.h:119
if(TDesc==NULL)
Definition: cd.c:1326
#define ERROR(CODE, MESSAGE)
Definition: util.h:66
int NIpzK_mag
Definition: nipzmeth.c:21
Definition: cddefs.h:169
#define OK
Definition: iferrmsg.h:17
Definition: cddefs.h:237
double NIpzK
Definition: nipzmeth.c:20
void zaddeq()
Definition: sced.h:120
static double c
Definition: vectors.c:16
CKTpzTrapped
Definition: pzstr.c:88
#define FABS(a)
Definition: util.h:41
return(True)
Definition: cddefs.h:227
#define DEBUG(N)
Definition: nipzmeth.c:14

Variable Documentation

CKTpzTrapped

Definition at line 88 of file pzstr.c.

double NIpzK

Definition at line 20 of file nipzmeth.c.

int NIpzK_mag

Definition at line 21 of file nipzmeth.c.