Skip to content

Commit

Permalink
Modified the code in ext2spice.c that prints parameter values;
Browse files Browse the repository at this point in the history
the former code attempted to determine the precision and generate
an output without unnecessary trailing zeros.  Unfortunately there
were counterexamples that fail to be formatted correctly, as found
by Mark Martin, and which generate output that has roundoff error.
Reimplemented the method using code found on StackOverflow, which
appears to solve the problem more robustly.
  • Loading branch information
RTimothyEdwards committed Jan 6, 2025
1 parent 32138cc commit 3df2aaa
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 17 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.3.510
8.3.511
101 changes: 85 additions & 16 deletions ext2spice/ext2spice.c
Original file line number Diff line number Diff line change
Expand Up @@ -3123,6 +3123,85 @@ FILE *outf;
}
}

/*
* ----------------------------------------------------------------------------
*
* nDecimals() ---
*
* Code taken from discussion at
* https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf
*
* Modifies value "d" by truncating it to precision "n", writing the result
* into string "s".
*
* ----------------------------------------------------------------------------
*/

void
nDecimals(char *s, double d, int n)
{
int sz;
double d2;

// Allow for negative.
d2 = (d >= 0) ? d : -d;
sz = (d >= 0) ? 0 : 1;

// Add one for each whole digit (0.xx special case).
if (d2 < 1) sz++;
while (d2 >= 1)
{
d2 /= 10.0;
sz++;
}

// Adjust for decimal point and fractionals.
sz += 1 + n;

// Create formatted string then use it.
sprintf(s, "%*.*f", sz, n, d);
}

/*
* ----------------------------------------------------------------------------
*
* morphNumericString() ---
*
* Code taken from discussion at
* https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf
*
* Remove trailing zeros from the number represented in string "s".
* Assume a precision (defined as precision after the decimal point) of "n".
*
* ----------------------------------------------------------------------------
*/

void
morphNumericString(char *s, int n)
{
char *p;
int count;

p = strchr (s, '.'); // Find decimal point, if any.
if (p != NULL)
{
count = n; // Adjust for more or less decimals.
while (count >= 0) // Maximum decimals allowed.
{
count--;
if (*p == '\0') // If there's less than desired.
break;
p++; // Next character.
}
*p-- = '\0'; // Truncate string.
while (*p == '0') // Remove trailing zeros.
*p-- = '\0';

if (*p == '.') // If all decimals were zeros, remove ".".
*p = '\0';
}
}

/*
* ----------------------------------------------------------------------------
*
Expand All @@ -3145,6 +3224,7 @@ esSIvalue(file, value)
FILE *file;
float value;
{
char vstr[32];
char suffix = '\0';
int precision;
float avalue;
Expand Down Expand Up @@ -3195,27 +3275,16 @@ esSIvalue(file, value)
/* Note that "%g" is preferred because it produces more readable
* output. However, it changes the definition of the precision
* from significant digits after the radix to total significant
* digits. Determine the proper precision to use by reading
* back the formatted value and comparing to the original value.
* digits. Using a solution provided in StackOverflow (see above).
*/

for (precision = 3; precision < 9; precision++)
{
int vtrunc, ptrunc;
char ptest[32];
float pvalue;

sprintf(ptest, "%.*g", precision, value);
sscanf(ptest, "%f", &pvalue);
vtrunc = (int)(0.5 + (value * 1e6));
ptrunc = (int)(0.5 + (pvalue * 1e6));
if (vtrunc == ptrunc) break;
}
nDecimals(vstr, (double)value, 5);
morphNumericString(vstr, 5);

if (suffix == '\0')
fprintf(file, "%.*g", precision, value);
fprintf(file, "%s", vstr);
else
fprintf(file, "%.*g%c", precision, value, suffix);
fprintf(file, "%s%c", vstr, suffix);
}

/*
Expand Down

0 comments on commit 3df2aaa

Please sign in to comment.