On 2010-08-05,
<> wrote:
> 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
Wait, 3000 or 3EEE?
More interestingly...
> 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.
When I run this, I get:
0;400000000000000000000000000000000000000000000000 00000000000000000000
00000000000000000000000000000000000000000000000000 00000000000000000000
00000000000000000000000000000000000000000000000000 00000000000000000000
00000000000000000000000000000000000000000000000000 00000000000000000000
00000000000000000000000000000
(line breaks added).
This may have to do with the value of DBL_MAX_10_EXP being different
on different targets, but I remain a bit confused.
> 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;
> }
> }
This seems like it should be irrelevant, because after all, it wouldn't
be able to generate E's from whole cloth.
Let's remove it, for now, since it's irrelevant (we hope) in this case.
> 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';
> }
> }
It isn't obvious why you use 'char' num instead of, say, 'int' num here,
but looks harmless.
> 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;
After you have done this, 'partholder' and 'decnum' are identical. I would
say drop one of them.
> while (wholedec >= 12) {
> *(doznum+(i++)) = dozenify(fmod(wholedec,12.0));
> wholedec /= 12;
> }
Okay, you're doing floating point math where you don't need to, but okay.
> *(doznum+(i++)) = dozenify(fmod(wholedec,12));
> if (sign == 1)
> *(doznum+(i++)) = '-';
> *(doznum+i) = '\0';
> reverse(doznum);
And we can remove this "reverse" and it shouldn't matter (for this specific
case) and further simplifies the code. And in any event, it doesn't seem
that this part is producing "wrong" results.
> 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;
> }
Hmm.
Seems to me you could simplify this quite a bit. Let's assume we're not
concerned with the accuracy of the whole result, but merely with reproducing
the apparent bug.
int dectodoz(char *doznum, double decnum)
{
int i = 0;
double wholedec; /* whole number portion of decnum */
decnum = modf(decnum,&wholedec);
if (decnum > 0) {
*(doznum++) = ';';
for (i=0; i <= DBL_MAX_10_EXP; ++i) {
*(doznum++) = dozenify((int)(decnum * 12));
decnum = modf(decnum*12,&wholedec);
}
*(doznum++) = '\0';
}
return 0;
}
This seems as though it should do the same thing. We drop the unneeded
elaborate indexing into doznum. (Since it's a parameter, we're working
with a local copy of the pointer, so we can just iterate through it.)
This produces the same results, for me. We can even clean up that inner
loop a bit more:
decnum = modf(decnum * 12, &wholedec);
*(doznum++) = dozenify(wholedec);
And I still get the same results.
-s
--
Copyright 2010, all wrongs reversed. Peter Seebach /
usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!