Browse Source

Using a real double compare to equal.

pre-master-46
dwarning 19 years ago
parent
commit
28e90e6330
  1. 9
      ChangeLog
  2. 12
      src/frontend/measure.c
  3. 2
      src/include/missing_math.h
  4. 53
      src/misc/missing_math.c
  5. 2
      src/misc/missing_math.h
  6. 8
      src/spicelib/analysis/dctran.c

9
ChangeLog

@ -1,9 +1,16 @@
2008-01-02 Dietmar Warning
* src/frontend/outitf.c: Fixed rawfile ascii generation. Same like below.
* src/frontend/inp.c: don't need local buffer w/o getcwd
* src/conf.c: belong spice3 manual ascii is default anyway
* src/misc/missing_math.*, src/include/missig_math.h, /src/frontend/measure.c,
src/spicelib/analysis/dctran.c: Using a real double compare to equal.
2008-01-02 Paolo Nenzi <p.nenzi@ieee.org> 2008-01-02 Paolo Nenzi <p.nenzi@ieee.org>
* src/frontend/rawfile.c: Fixed rawfile ascii generation. The prevoius patch * src/frontend/rawfile.c: Fixed rawfile ascii generation. The prevoius patch
produced incorrect string like v(v(1)) for v(1) in the output file. produced incorrect string like v(v(1)) for v(1) in the output file.
2007-12-31 Holger Vogt 2007-12-31 Holger Vogt
* src/frontend/com_chdir.c: fix for the crashing of ngspice under Windows when
don't need buffer w/o getcwd fix for the crashing of ngspice under Windows when
started from windows explorer. started from windows explorer.
* src/frontend/inp.c: ngspice crashed when executing a file consisting of a simple * src/frontend/inp.c: ngspice crashed when executing a file consisting of a simple
control section. Fixed. control section. Fixed.

12
src/frontend/measure.c

@ -74,7 +74,7 @@ get_volt_time( struct dvec *time, struct dvec *values, double value, char polari
*failed = TRUE; *failed = TRUE;
} }
} }
if ( AlmostEqualUlps( comp_time, 0, 3 ) ) *failed = TRUE;
if ( AlmostEqualUlps( comp_time, 0, 100 ) ) *failed = TRUE;
return comp_time; return comp_time;
} }
@ -139,7 +139,7 @@ measure2( char *meas_type, char *vec_name, char vec_type, double from, double to
*result_time = time->v_realdata[i]; *result_time = time->v_realdata[i];
} else { } else {
*result = ( strcmp( meas_type, "max" ) == 0 ) ? max( *result, vec->v_realdata[i] ) : min( *result, vec->v_realdata[i] ); *result = ( strcmp( meas_type, "max" ) == 0 ) ? max( *result, vec->v_realdata[i] ) : min( *result, vec->v_realdata[i] );
if ( !AlmostEqualUlps( prev_result, *result, 3 ) ) *result_time = time->v_realdata[i];
if ( !AlmostEqualUlps( prev_result, *result, 100 ) ) *result_time = time->v_realdata[i];
} }
} }
} }
@ -164,23 +164,23 @@ measure2( char *meas_type, char *vec_name, char vec_type, double from, double to
// see if y-value constant // see if y-value constant
for ( i = 0; i < xy_size-1; i++ ) for ( i = 0; i < xy_size-1; i++ )
if ( !AlmostEqualUlps( *(y+i), *(y+i+1), 3 ) ) constant_y = FALSE;
if ( !AlmostEqualUlps( *(y+i), *(y+i+1), 100 ) ) constant_y = FALSE;
// Compute Integral (area under curve) // Compute Integral (area under curve)
i = 0; i = 0;
while ( i < xy_size-1 ) { while ( i < xy_size-1 ) {
// Simpson's 3/8 Rule // Simpson's 3/8 Rule
if ( AlmostEqualUlps( *(width+i), *(width+i+1), 3 ) && AlmostEqualUlps( *(width+i), *(width+i+2), 3 ) ) {
if ( AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) && AlmostEqualUlps( *(width+i), *(width+i+2), 100 ) ) {
sum1 += 3*(*(width+i))*(*(y+i) + 3*(*(y+i+1) + *(y+i+2)) + *(y+i+3))/8; sum1 += 3*(*(width+i))*(*(y+i) + 3*(*(y+i+1) + *(y+i+2)) + *(y+i+3))/8;
i += 3; i += 3;
} }
// Simpson's 1/3 Rule // Simpson's 1/3 Rule
else if ( AlmostEqualUlps( *(width+i), *(width+i+1), 3 ) ) {
else if ( AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) ) {
sum2 += *(width+i)*(*(y+i) + 4*(*(y+i+1)) + *(y+i+2))/3; sum2 += *(width+i)*(*(y+i) + 4*(*(y+i+1)) + *(y+i+2))/3;
i += 2; i += 2;
} }
// Trapezoidal Rule // Trapezoidal Rule
else if ( !AlmostEqualUlps( *(width+i), *(width+i+1), 3 ) ) {
else if ( !AlmostEqualUlps( *(width+i), *(width+i+1), 100 ) ) {
sum3 += *(width+i)*(*(y+i) + *(y+i+1))/2; sum3 += *(width+i)*(*(y+i) + *(y+i+1))/2;
i++; i++;
} }

2
src/include/missing_math.h

@ -8,7 +8,7 @@ Copyright 1999 Emmanuel Rouat
#ifndef MISSING_MATH_H_INCLUDED #ifndef MISSING_MATH_H_INCLUDED
#define MISSING_MATH_H_INCLUDED #define MISSING_MATH_H_INCLUDED
bool AlmostEqualUlps(float, float, int);
bool AlmostEqualUlps(double, double, int);
#ifndef HAVE_ERFC #ifndef HAVE_ERFC
extern double erfc(double); extern double erfc(double);

53
src/misc/missing_math.c

@ -11,22 +11,59 @@ $Id$
#include "ngspice.h" #include "ngspice.h"
#include "missing_math.h" #include "missing_math.h"
#ifdef _MSC_VER
typedef __int64 long64;
#else
typedef long long long64;
#endif
#define Abs(x) ((x) < 0 ? -(x) : (x))
/* Initial AlmostEqualULPs version - fast and simple, but */
/* some limitations. */
bool AlmostEqualUlps(float A, float B, int maxUlps)
/* From Bruce Dawson, Comparing floating point numbers,
http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm
Original this function is named AlmostEqual2sComplement but we leave it to AlmostEqualUlps
and can leave the code (measure.c, dctran.c) unchanged. The transformation to the 2's complement
prevent problems around 0.0.
One Ulp is equivalent to a maxRelativeError of between 1/4,000,000,000,000,000 and 1/8,000,000,000,000,000.
Practical: 3 < maxUlps < some hundred's (or thousand's) - depending on numerical requirements.
*/
bool AlmostEqualUlps(double A, double B, int maxUlps)
{ {
int intDiff;
assert(sizeof(float) == sizeof(int));
long64 aInt, bInt, intDiff;
if (A == B) if (A == B)
return TRUE; return TRUE;
intDiff = abs(*(int*)&A - *(int*)&B);
/* If not - the entire method can not work */
assert(sizeof(double) == sizeof(long64));
/* Make sure maxUlps is non-negative and small enough that the */
/* default NAN won't compare as equal to anything. */
assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
aInt = *(long64*)&A;
/* Make aInt lexicographically ordered as a twos-complement int */
if (aInt < 0)
#ifdef _MSC_VER
aInt = 0x8000000000000000 - aInt;
#else
aInt = 0x8000000000000000LL - aInt;
#endif
bInt = *(long64*)&B;
/* Make bInt lexicographically ordered as a twos-complement int */
if (bInt < 0)
#ifdef _MSC_VER
bInt = 0x8000000000000000 - bInt;
#else
bInt = 0x8000000000000000LL - bInt;
#endif
#ifdef _MSC_VER
intDiff = Abs(aInt - bInt);
#else
intDiff = llabs(aInt - bInt);
#endif
/* printf("A:%e B:%e aInt:%d bInt:%d diff:%d\n", A, B, aInt, bInt, intDiff); */
if (intDiff <= maxUlps) if (intDiff <= maxUlps)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }

2
src/misc/missing_math.h

@ -6,7 +6,7 @@
#ifndef MISSING_MATH_H_INCLUDED #ifndef MISSING_MATH_H_INCLUDED
#define MISSING_MATH_H_INCLUDED #define MISSING_MATH_H_INCLUDED
bool AlmostEqualUlps(float, float, int);
bool AlmostEqualUlps(double, double, int);
#ifndef HAVE_ERFC #ifndef HAVE_ERFC
double erfc(double); double erfc(double);

8
src/spicelib/analysis/dctran.c

@ -459,7 +459,7 @@ nextTime:
ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter; ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter;
if(check_autostop("tran") || if(check_autostop("tran") ||
fabs(ckt->CKTtime - ckt->CKTfinalTime) < ckt->CKTminBreak || fabs(ckt->CKTtime - ckt->CKTfinalTime) < ckt->CKTminBreak ||
AlmostEqualUlps( ckt->CKTtime, ckt->CKTfinalTime, 3 ) ) {
AlmostEqualUlps( ckt->CKTtime, ckt->CKTfinalTime, 100 ) ) {
#ifdef STEPDEBUG #ifdef STEPDEBUG
printf(" done: time is %g, final time is %g, and tol is %g\n", printf(" done: time is %g, final time is %g, and tol is %g\n",
ckt->CKTtime,ckt->CKTfinalTime,ckt->CKTminBreak); ckt->CKTtime,ckt->CKTfinalTime,ckt->CKTminBreak);
@ -526,7 +526,7 @@ resume:
#ifdef XSPICE #ifdef XSPICE
/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */ /* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */
//if(ckt->CKTtime == g_mif_info.breakpoint.last) //if(ckt->CKTtime == g_mif_info.breakpoint.last)
if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 3 ) )
if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 100 ) )
ckt->CKTorder = 1; ckt->CKTorder = 1;
/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */ /* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */
@ -535,7 +535,7 @@ resume:
/* are we at a breakpoint, or indistinguishably close? */ /* are we at a breakpoint, or indistinguishably close? */
//if ((ckt->CKTtime == *(ckt->CKTbreaks)) || (*(ckt->CKTbreaks) - //if ((ckt->CKTtime == *(ckt->CKTbreaks)) || (*(ckt->CKTbreaks) -
if ( AlmostEqualUlps( ckt->CKTtime, *(ckt->CKTbreaks), 3 ) || (*(ckt->CKTbreaks) -
if ( AlmostEqualUlps( ckt->CKTtime, *(ckt->CKTbreaks), 100 ) || (*(ckt->CKTbreaks) -
(ckt->CKTtime) <= ckt->CKTdelmin)) { (ckt->CKTtime) <= ckt->CKTdelmin)) {
/* first timepoint after a breakpoint - cut integration order */ /* first timepoint after a breakpoint - cut integration order */
/* and limit timestep to .1 times minimum of time to next breakpoint, /* and limit timestep to .1 times minimum of time to next breakpoint,
@ -589,7 +589,7 @@ resume:
#ifdef STEPDEBUG #ifdef STEPDEBUG
printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n",*(ckt->CKTbreaks), ckt->CKTtime, ckt->CKTminBreak); printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n",*(ckt->CKTbreaks), ckt->CKTtime, ckt->CKTminBreak);
#endif #endif
if(AlmostEqualUlps(*(ckt->CKTbreaks),ckt->CKTtime,3) || *(ckt->CKTbreaks) <= (ckt->CKTtime + ckt->CKTminBreak)) {
if(AlmostEqualUlps(*(ckt->CKTbreaks),ckt->CKTtime, 100) || *(ckt->CKTbreaks) <= (ckt->CKTtime + ckt->CKTminBreak)) {
#ifdef STEPDEBUG #ifdef STEPDEBUG
printf("throwing out permanent breakpoint times <= current time (brk pt: %g)\n",*(ckt->CKTbreaks)); printf("throwing out permanent breakpoint times <= current time (brk pt: %g)\n",*(ckt->CKTbreaks));
printf(" ckt_time: %g ckt_min_break: %g\n",ckt->CKTtime, ckt->CKTminBreak); printf(" ckt_time: %g ckt_min_break: %g\n",ckt->CKTtime, ckt->CKTminBreak);

Loading…
Cancel
Save