Hi pdftex fans,
function convertNumToPDF() has the feature, that if it gets numbers with
6 nonzero digits after the decimal point, it will not append a '\0' to
the number string in the buffer. Then you get more than 6 digits after
the point: whatever is left in the buffer until the next '\0'. And the
rounding isn't clear. In the patched version below the rounding is at
+/- 1/2 eps; the check for small numbers can be omitted by the way.
Here is the output from the test program below for some numbers:
input <orig> <patched>
10.00005000 <10.000049> <10.00005>
2.12345600 <2.1234569> <2.123456>
0.00000040 <0> <0>
0.00000050 <0> <0.000001>
0.00000100 <0.0000019> <0.000001>
9.00000000 <9> <9>
9.99999940 <9.9999999> <9.999999>
9.99999950 <9.9999999> <10>
9.99999990 <9.9999999> <10>
10.00000040 <10> <10>
10.00000050 <10> <10.000001>
10.00000100 <10> <10.000001>
10.00000200 <10.000002> <10.000002>
9.99999990 <9.9999992> <10>
9.49999949 <9.4999992> <9.499999>
9.49999950 <9.4999992> <9.5>
9.49999951 <9.4999992> <9.5>
Below is the program for producing this list with the patch. Have fun.
Greetings Hartmut
#include
#include
#include
static char *convertNumToPDF_orig(double n)
{
/* converts double to string; very small and very large numbers are NOT
* converted to scientific notation.
* n must be a number or real confirming to the implementation limits of
* PDF as specified in appendix C.1 of the pdf ref.
* These are:
* maximum value of ints is +2^32
* maximum value of reals is +2^15
* smalles values of reals is 1/(2^16)
*/
static int precision = 6;
static int fact = (int) 1E6; /* must be 10^precision */
static double epsilon = 1E-6; /* must be 10^-precision */
static char buf[64];
// handle very small values: return 0
if (fabs(n) < epsilon) {
buf[0] = '0';
buf[1] = '\0';
} else {
char ints[64];
int bindex = 0, sindex = 0;
int ival, fval, i;
// handle the sign part if n is negative
if (n < 0) {
buf[bindex++] = '-';
n = -n;
}
// handle the integer part, simply with sprintf
ival = (int) floor(n);
n -= ival;
sprintf(ints, "%d", ival);
while (ints[sindex] != 0)
buf[bindex++] = ints[sindex++];
// handle the fractional part up to 'precision' digits
fval = (int) floor(n * fact);
if (fval) {
// set a dot
buf[bindex++] = '.';
sindex = bindex + precision - 1;
// fill up trailing zeros with the string terminator NULL
while (((fval % 10) == 0) && (sindex >= bindex)) {
buf[sindex--] = '\0';
fval /= 10;
}
// fill up the fractional part back to front
while (sindex >= bindex) {
buf[sindex--] = (fval % 10) + '0';
fval /= 10;
}
} else
buf[bindex++] = 0;
}
return (char *) buf;
}
static char *convertNumToPDF(double n)
{
/* converts double to string; very small and very large numbers are NOT
* converted to scientific notation.
* n must be a number or real confirming to the implementation limits of
* PDF as specified in appendix C.1 of the pdf ref.
* These are:
* maximum value of ints is +2^32
* maximum value of reals is +2^15
* smalles values of reals is 1/(2^16)
*/
static int precision = 6;
static int fact = (int) 1E6; /* must be 10^precision */
static double epsilon = 1E-6; /* must be 10^-precision */
static char buf[64];
char ints[64];
int bindex = 0, sindex = 0;
int ival, fval, i;
// handle the sign part if n is negative
if (n < 0) {
buf[bindex++] = '-';
n = -n;
}
// handle the integer part, simply with sprintf
n += 0.5 * epsilon;
ival = (int) floor(n);
n -= ival;
sprintf(ints, "%d", ival);
while (ints[sindex] != 0)
buf[bindex++] = ints[sindex++];
// handle the fractional part up to 'precision' digits
fval = (int) floor(n * fact);
if (fval) {
// set a dot
buf[bindex++] = '.';
sindex = bindex + precision;
buf[sindex--] = '\0';
// fill up trailing zeros with the string terminator NULL
while (((fval % 10) == 0) && (sindex >= bindex)) {
buf[sindex--] = '\0';
fval /= 10;
}
// fill up the fractional part back to front
while (sindex >= bindex) {
buf[sindex--] = (fval % 10) + '0';
fval /= 10;
}
} else
buf[bindex++] = 0;
return (char *) buf;
}
int main()
{
double z[] =
{ 10.00005, 2.123456, 0.0000004, 0.0000005, 0.000001, 9, 9.9999994,
9.9999995,
9.9999999, 10.0000004, 10.0000005, 10.000001, 10.000002, 9.9999999,
9.49999949, 9.4999995, 9.49999951
};
char *buf_orig, *buf;
int i;
printf("input <orig> <patched>\n");
for (i = 0; i < 17; i++) {
buf_orig = convertNumToPDF_orig(z[i]);
buf = convertNumToPDF(z[i]);
printf("%11.8f <%s> <%s>\n", z[i], buf_orig, buf);
}
return 0;
}