D
dgoodmaniii
Summary: code works correctly on x86_64; fails on i686;
both systems running the same kernel and the same operating
system. When running the code through valgrind, however, it
works on both systems. valgrind finds 0 errors in 0
contexts. A minimal example which reproduces this errors is
attached to the end.
To compile in all instances: gcc -lm -o doztest doztest.c
Long story: I'm writing a base-ten to base-twelve
converter, very simple, that works fine on my x86_64 box,
running Debian GNU/Linux (stable) on a 2.6.26 kernel. It
passed all my tests; in particularly, it correctly converted
this:
0.3333333333333333 --> 0;4000
When I cloned the repository and built it on my i686 box,
however, running the same Debian on the same kernel, this is
what came out:
0.3333333333333333 --> 0;3000
0.3333333333333 --> 0;3EEE
This is wrong, of course, but I can't figure out how. So I
ran the following:
valgrind -v --leak-check=full
followed by my program. It says there are 0 errors from 0
contexts; however, when run through valgrind the proper
answer comes out! That is, the code that produces this:
0.3333333333333333 --> 0;3000
when run by itself, produces this:
0.3333333333333333 --> 0;4000
when run through valgrind. I'm completely mystified. So I
isolated the code that seems to be causing the trouble,
which is the dectodoz function, which only calls two of my
own functions, and have posted it here as a minimal example.
This code reproduces the same strange results in all contexts.
#include<stdio.h>
#include<float.h>
#include<math.h>
#include<string.h>
void reverse(char *s)
{
int i, j;
char tmp;
size_t length;
length = strlen(s) - 1;
for (i=0, j=length; i<j; ++i, --j) {
tmp = *(s+i);
*(s+i) = *(s+j);
*(s+j) = tmp;
}
}
char dozenify(char num)
{
switch (num) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6:
case 7: case 8: case 9:
return (num % 10) + '0';
case 10:
return 'X';
case 11:
return 'E';
}
}
int dectodoz(char *doznum, double decnum)
{
int i = 0; int sign = 0; int j = 0;
double wholedec; /* whole number portion of decnum */
double partholder; /* someplace for modf to dump integral */
if (decnum < 0) {
decnum = -decnum;
sign = 1;
}
partholder = modf(decnum,&wholedec);
decnum -= wholedec;
while (wholedec >= 12) {
*(doznum+(i++)) = dozenify(fmod(wholedec,12.0));
wholedec /= 12;
}
*(doznum+(i++)) = dozenify(fmod(wholedec,12));
if (sign == 1)
*(doznum+(i++)) = '-';
*(doznum+i) = '\0';
reverse(doznum);
if (decnum > 0) {
*(doznum+(i++)) = ';';
for (i=i; i <= DBL_MAX_10_EXP; ++i) {
*(doznum+i) = dozenify((int)(decnum * 12));
decnum = modf(decnum*12,&partholder);
}
*(doznum+i) = '\0';
}
return 0;
}
int main(void)
{
char doznum[2000] = "";
double decnum = 0.33333333333333333333333333333333333;
dectodoz(doznum,decnum);
printf("%s\n",doznum);
return 0;
}
<<<<<<<
both systems running the same kernel and the same operating
system. When running the code through valgrind, however, it
works on both systems. valgrind finds 0 errors in 0
contexts. A minimal example which reproduces this errors is
attached to the end.
To compile in all instances: gcc -lm -o doztest doztest.c
Long story: I'm writing a base-ten to base-twelve
converter, very simple, that works fine on my x86_64 box,
running Debian GNU/Linux (stable) on a 2.6.26 kernel. It
passed all my tests; in particularly, it correctly converted
this:
0.3333333333333333 --> 0;4000
When I cloned the repository and built it on my i686 box,
however, running the same Debian on the same kernel, this is
what came out:
0.3333333333333333 --> 0;3000
0.3333333333333 --> 0;3EEE
This is wrong, of course, but I can't figure out how. So I
ran the following:
valgrind -v --leak-check=full
followed by my program. It says there are 0 errors from 0
contexts; however, when run through valgrind the proper
answer comes out! That is, the code that produces this:
0.3333333333333333 --> 0;3000
when run by itself, produces this:
0.3333333333333333 --> 0;4000
when run through valgrind. I'm completely mystified. So I
isolated the code that seems to be causing the trouble,
which is the dectodoz function, which only calls two of my
own functions, and have posted it here as a minimal example.
This code reproduces the same strange results in all contexts.
#include<stdio.h>
#include<float.h>
#include<math.h>
#include<string.h>
void reverse(char *s)
{
int i, j;
char tmp;
size_t length;
length = strlen(s) - 1;
for (i=0, j=length; i<j; ++i, --j) {
tmp = *(s+i);
*(s+i) = *(s+j);
*(s+j) = tmp;
}
}
char dozenify(char num)
{
switch (num) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6:
case 7: case 8: case 9:
return (num % 10) + '0';
case 10:
return 'X';
case 11:
return 'E';
}
}
int dectodoz(char *doznum, double decnum)
{
int i = 0; int sign = 0; int j = 0;
double wholedec; /* whole number portion of decnum */
double partholder; /* someplace for modf to dump integral */
if (decnum < 0) {
decnum = -decnum;
sign = 1;
}
partholder = modf(decnum,&wholedec);
decnum -= wholedec;
while (wholedec >= 12) {
*(doznum+(i++)) = dozenify(fmod(wholedec,12.0));
wholedec /= 12;
}
*(doznum+(i++)) = dozenify(fmod(wholedec,12));
if (sign == 1)
*(doznum+(i++)) = '-';
*(doznum+i) = '\0';
reverse(doznum);
if (decnum > 0) {
*(doznum+(i++)) = ';';
for (i=i; i <= DBL_MAX_10_EXP; ++i) {
*(doznum+i) = dozenify((int)(decnum * 12));
decnum = modf(decnum*12,&partholder);
}
*(doznum+i) = '\0';
}
return 0;
}
int main(void)
{
char doznum[2000] = "";
double decnum = 0.33333333333333333333333333333333333;
dectodoz(doznum,decnum);
printf("%s\n",doznum);
return 0;
}
<<<<<<<