Enable printing outputs with engineering exponents

This commit is contained in:
Holger Vogt 2026-04-26 12:08:08 +02:00
parent be9d1df1d2
commit 9007ffab23
6 changed files with 87 additions and 6 deletions

View File

@ -10,6 +10,7 @@ libmisc_la_SOURCES = \
dup2.c \
dstring.c \
dup2.h \
engnotation.c \
hash.c \
ivars.c \
ivars.h \

71
src/misc/engnotation.c Normal file
View File

@ -0,0 +1,71 @@
/* Print a floating-point number in engineering notation.
Documentation: http://www.cs.tut.fi/~jkorpela/c/eng.html
BSD-style license */
#define PREFIX_START (-24)
/* Smallest power of ten for which there is a prefix defined.
If the set of prefixes will be extended, change this constant
and update the table "prefix". */
#include <stdio.h>
#include <math.h>
#include "ngspice/ngspice.h"
/* Print a floating-point number in engineering notation.
Return string needs to be freed by the caller after its use.
numeric selects e3, e6, e9 etc. or k, M, G etc. */
char *eng(double value, int digits, int numeric)
{
static char *prefix[] = {
"y", "z", "a", "f", "p", "n", "u", "m", "",
"k", "M", "G", "T", "P", "E", "Z", "Y"
};
#define PREFIX_END (PREFIX_START+\
(int)((sizeof(prefix)/sizeof(char *)-1)*3))
double display, fract;
int expof10;
char *result, *sign;
if(value < 0.0) {
sign = "-";
value = -value;
} else {
sign = "";
}
// correctly round to desired precision
expof10 = lrint( floor( log10(value) ) );
value *= pow(10.0, digits - 1 - expof10);
fract = modf(value, &display);
if(fract >= 0.5) display += 1.0;
value = display * pow(10.0, expof10 - digits + 1);
if(expof10 > 0)
expof10 = (expof10/3)*3;
else
expof10 = ((-expof10+3)/3)*(-3);
value *= pow(10.0, -expof10);
if (value >= 1000.0) {
value /= 1000.0;
expof10 += 3;
}
else if(value >= 100.0)
digits -= 2;
else if(value >= 10.0)
digits -= 1;
if(numeric || (expof10 < PREFIX_START) || (expof10 > PREFIX_END))
if (expof10 == 0)
result = tprintf("%s%.*f", sign, digits-1, value);
else
result = tprintf("%s%.*fe%d", sign, digits-1, value, expof10);
else
result = tprintf("%s%.*f %s", sign, digits-1, value, prefix[(expof10-PREFIX_START)/3]);
return result;
}

View File

@ -24,6 +24,8 @@
/* gtri - end - wbk - Add headers */
#endif
extern char* eng(double value, int digits, int numeric);
#define INIT_STATS() \
do { \
startTime = SPfrontEnd->IFseconds(); \
@ -625,6 +627,8 @@ DCpss(CKTcircuit *ckt,
/* If evolution is near shooting... */
if ((AlmostEqualUlps (ckt->CKTtime, time_temp + 1 / ckt->CKTguessedFreq, 10)) || (ckt->CKTtime > time_temp + 1 / ckt->CKTguessedFreq))
{
char* freq = NULL;
int excessive_err_nodes = 0 ;
/* Calculation of error norms of RHS solution of every accepted nextTime */
@ -798,8 +802,9 @@ DCpss(CKTcircuit *ckt,
rr_history [shooting_cycle_counter] = err ;
gf_history [shooting_cycle_counter] = ckt->CKTguessedFreq ;
shooting_cycle_counter++ ;
fprintf (stdout, "Updated guessed frequency: %1.10lg .\n", ckt->CKTguessedFreq) ;
freq = eng(ckt->CKTguessedFreq, 10, 1);
fprintf (stdout, "Updated guessed frequency: %s Hz.\n", freq) ;
tfree(freq);
fprintf (stdout, "Next shooting evaluation time is %1.10g and current time is %1.10g.\n",
time_temp + 1 / ckt->CKTguessedFreq, ckt->CKTtime) ;
@ -835,8 +840,7 @@ shootingexit:
if ((shooting_cycle_counter > ckt->CKTsc_iter) || (excessive_err_nodes == 0))
{
int k ;
double minimum ;
double minimum;
pss_state = PSS ;
#ifdef PSSDEBUG
@ -880,10 +884,12 @@ shootingexit:
pss_points_cycle++ ;
CKTsetBreak (ckt, time_temp + (1 / ckt->CKTguessedFreq) * ((double)pss_points_cycle / (double)ckt->CKTpsspoints)) ;
freq = eng(ckt->CKTguessedFreq, 10, 1); /* engineering notation */
if (excessive_err_nodes == 0)
fprintf (stdout, "\nConvergence reached. Final circuit time is %1.10g seconds (iteration n° %d) and predicted fundamental frequency is %15.10g Hz\n", ckt->CKTtime, shooting_cycle_counter - 1, ckt->CKTguessedFreq) ;
fprintf (stdout, "\nConvergence reached. Final circuit time is %1.10g seconds (iteration n° %d) and predicted fundamental frequency is %s Hz\n", ckt->CKTtime, shooting_cycle_counter - 1, freq) ;
else
fprintf (stdout, "\nConvergence not reached. However the most near convergence iteration has predicted (iteration %d) a fundamental frequency of %15.10g Hz\n", k, ckt->CKTguessedFreq) ;
fprintf (stdout, "\nConvergence not reached. However the most near convergence iteration has predicted (iteration %d) a fundamental frequency of %s Hz\n", k, freq) ;
tfree(freq);
#ifdef PSSDEBUG
fprintf (stderr, "time_temp %g\n", time_temp) ;

View File

@ -1454,6 +1454,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
<ClCompile Include="..\src\misc\alloc.c" />
<ClCompile Include="..\src\misc\dstring.c" />
<ClCompile Include="..\src\misc\dup2.c" />
<ClCompile Include="..\src\misc\engnotation.c" />
<ClCompile Include="..\src\misc\getopt_long_bsd.c" />
<ClCompile Include="..\src\misc\hash.c" />
<ClCompile Include="..\src\misc\ivars.c" />

View File

@ -1675,6 +1675,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
<ClCompile Include="..\src\misc\alloc.c" />
<ClCompile Include="..\src\misc\dstring.c" />
<ClCompile Include="..\src\misc\dup2.c" />
<ClCompile Include="..\src\misc\engnotation.c" />
<ClCompile Include="..\src\misc\getopt_long_bsd.c" />
<ClCompile Include="..\src\misc\hash.c" />
<ClCompile Include="..\src\misc\ivars.c" />

View File

@ -1690,6 +1690,7 @@
<ClCompile Include="..\src\misc\alloc.c" />
<ClCompile Include="..\src\misc\dstring.c" />
<ClCompile Include="..\src\misc\dup2.c" />
<ClCompile Include="..\src\misc\engnotation.c" />
<ClCompile Include="..\src\misc\getopt_long_bsd.c" />
<ClCompile Include="..\src\misc\hash.c" />
<ClCompile Include="..\src\misc\ivars.c" />