Strange bit corruption in a double

D

Digital Puer

I'm getting a very weird bit corruption in a double. I am on an Intel
Red Hat Linux box. uname -a returns:
Linux foo.com 2.6.9-34.0.2.ELsmp #1 SMP Fri Jun 30 10:33:58 EDT 2006
i686 i686 i386 GNU/Linux

I have a "double" variable that is set to 0.00. Some number
crunching then occurs, and later on, when I printf this variable
with printf("%f"), I am getting 0.00000.

However, when I compare
if (variable == 0.0), I get false.
and if (variable > 0.0), I get true.

I then ran a small function to print the bits of this variable and
found that its bit pattern is quite odd:

printf = 0.000000000000000
bits = 11001000 00010100 00010100 00001001 10001100 00000010 10111110
00000000

Any ideas??????



FWIW, I know the function to print the bit pattern of the double
is correct:

void print_binary_double(double value)
{
unsigned char *a;
a = (unsigned char *)&value;

int bytes = sizeof(double);
for (int i = 0; i < bytes; i++) {
print_binary_uc(*a);
printf(" ");
a++;
}
printf("\n");
}
void print_binary_uc(unsigned char value)
{
unsigned char value2;
int i;
int len = sizeof(unsigned char) * 8;
for (i = len-1; i >= 0; i--)
{
value2 = value & ((unsigned char)1 << i);
printf("%d", value2 ? 1 : 0);
}
}
 
D

David T. Ashley

Digital Puer said:
I'm getting a very weird bit corruption in a double. I am on an Intel
Red Hat Linux box. uname -a returns:
Linux foo.com 2.6.9-34.0.2.ELsmp #1 SMP Fri Jun 30 10:33:58 EDT 2006
i686 i686 i386 GNU/Linux

I have a "double" variable that is set to 0.00. Some number
crunching then occurs, and later on, when I printf this variable
with printf("%f"), I am getting 0.00000.

However, when I compare
if (variable == 0.0), I get false.
and if (variable > 0.0), I get true.

I haven't analyzed the bit pattern you provided, but the information you've
presented isn't consistent with "corruption".

Assume that the number is positive, but very small (let's say 10^(-30)).
Then no version of printf with a practical number of decimal places will
show anything but zero. Additionally, it would test as positive as you
indicated above.

In order to print this number, you'd to use the "%e" rather than the "%f"
format specifier.

Most binary scientific notation (i.e. float, double) formats contain a
binary exponent, which I suspect in this case is a very negative number.
The fact that there are a lot of "1"s set in the number are not inconsistent
with a very small positive number.

Try "%e", and post your results ...
 
L

Lane Straatman

Digital Puer said:
I'm getting a very weird bit corruption in a double. I am on an Intel
Red Hat Linux box. uname -a returns:
Linux foo.com 2.6.9-34.0.2.ELsmp #1 SMP Fri Jun 30 10:33:58 EDT 2006
i686 i686 i386 GNU/Linux

I have a "double" variable that is set to 0.00. Some number
crunching then occurs, and later on, when I printf this variable
with printf("%f"), I am getting 0.00000.

However, when I compare
if (variable == 0.0), I get false.
and if (variable > 0.0), I get true.

I then ran a small function to print the bits of this variable and
found that its bit pattern is quite odd:

printf = 0.000000000000000
bits = 11001000 00010100 00010100 00001001 10001100 00000010 10111110
00000000

Any ideas??????



FWIW, I know the function to print the bit pattern of the double
is correct:

void print_binary_double(double value)
{
unsigned char *a;
a = (unsigned char *)&value;

int bytes = sizeof(double);
for (int i = 0; i < bytes; i++) {
print_binary_uc(*a);
printf(" ");
a++;
}
printf("\n");
}
void print_binary_uc(unsigned char value)
{
unsigned char value2;
int i;
int len = sizeof(unsigned char) * 8;
for (i = len-1; i >= 0; i--)
{
value2 = value & ((unsigned char)1 << i);
printf("%d", value2 ? 1 : 0);
}
}
I'll bet your format specifier needs tweeking. The source is sloppy-looking
too. LS
 
R

Richard Heathfield

Lane Straatman said:
Whitespace.

man indent if you care enough. Yes, whitespace matters, but it can be added
automatically and trivially to your exact requirements. I have my own
whitespace preferences, which not everybody shares, but "layout not in
accord with my preferences" and "sloppy-looking" are different concepts.
 
B

Ben Bacarisse

Digital Puer said:
I'm getting a very weird bit corruption in a double. I am on an Intel
Red Hat Linux box. uname -a returns:
Linux foo.com 2.6.9-34.0.2.ELsmp #1 SMP Fri Jun 30 10:33:58 EDT 2006
i686 i686 i386 GNU/Linux

I have a "double" variable that is set to 0.00. Some number
crunching then occurs, and later on, when I printf this variable
with printf("%f"), I am getting 0.00000.

However, when I compare
if (variable == 0.0), I get false.
and if (variable > 0.0), I get true.

I then ran a small function to print the bits of this variable and
found that its bit pattern is quite odd:

printf = 0.000000000000000
bits = 11001000 00010100 00010100 00001001 10001100 00000010 10111110
00000000

Any ideas??????

There are lots of numbers that are consistent with this data. Any
number too small to have a non-zero decimal digit in the default
precision used by %f format may still be very much != 0.0 and > 0.0.

I think your bit pattern represents a number in the order of
4.3e-305. The %g format will print it as will (on my gcc) %.310f!
 
J

Joe Wright

Digital said:
I'm getting a very weird bit corruption in a double. I am on an Intel
Red Hat Linux box. uname -a returns:
Linux foo.com 2.6.9-34.0.2.ELsmp #1 SMP Fri Jun 30 10:33:58 EDT 2006
i686 i686 i386 GNU/Linux

I have a "double" variable that is set to 0.00. Some number
crunching then occurs, and later on, when I printf this variable
with printf("%f"), I am getting 0.00000.

However, when I compare
if (variable == 0.0), I get false.
and if (variable > 0.0), I get true.

I then ran a small function to print the bits of this variable and
found that its bit pattern is quite odd:

printf = 0.000000000000000
bits = 11001000 00010100 00010100 00001001 10001100 00000010 10111110
00000000

Any ideas??????



FWIW, I know the function to print the bit pattern of the double
is correct:

void print_binary_double(double value)
{
unsigned char *a;
a = (unsigned char *)&value;

int bytes = sizeof(double);
for (int i = 0; i < bytes; i++) {
print_binary_uc(*a);
printf(" ");
a++;
}
printf("\n");
}
void print_binary_uc(unsigned char value)
{
unsigned char value2;
int i;
int len = sizeof(unsigned char) * 8;
for (i = len-1; i >= 0; i--)
{
value2 = value & ((unsigned char)1 << i);
printf("%d", value2 ? 1 : 0);
}
}
You've got something cocked up. I get..

11001000 00010100 00010100 00001001 10001100 00000010 10111110 00000000
Exp = 1153 (131)
000 10000011
Man = .10100 00010100 00001001 10001100 00000010 10111110 00000000
-1.7080703671901993e+39

...from your 'bits' above.
 
J

Joe Wright

Ben said:
There are lots of numbers that are consistent with this data. Any
number too small to have a non-zero decimal digit in the default
precision used by %f format may still be very much != 0.0 and > 0.0.

I think your bit pattern represents a number in the order of
4.3e-305. The %g format will print it as will (on my gcc) %.310f!
No Ben. There is only one value consistent with the 'bits' data as
presented. It is a 64-bit double on x86 architecture and is unique.

This particular value, expressed by 'printf(".16e", v)' is..

-1.7080703671901993e+39

...precisely.
 
B

Barry Schwarz

I'm getting a very weird bit corruption in a double. I am on an Intel
Red Hat Linux box. uname -a returns:
Linux foo.com 2.6.9-34.0.2.ELsmp #1 SMP Fri Jun 30 10:33:58 EDT 2006
i686 i686 i386 GNU/Linux

I have a "double" variable that is set to 0.00. Some number
crunching then occurs, and later on, when I printf this variable
with printf("%f"), I am getting 0.00000.

However, when I compare
if (variable == 0.0), I get false.
and if (variable > 0.0), I get true.

I then ran a small function to print the bits of this variable and
found that its bit pattern is quite odd:

printf = 0.000000000000000
bits = 11001000 00010100 00010100 00001001 10001100 00000010 10111110
00000000

Any ideas??????

Others have explained why very small non-zero values will print as
zero.
FWIW, I know the function to print the bit pattern of the double
is correct:

Only if "correct" means specific to your system and either C99 or
extensions allowed.
void print_binary_double(double value)
{
unsigned char *a;
a = (unsigned char *)&value;

int bytes = sizeof(double);

C89 does not permit declarations after statements.
for (int i = 0; i < bytes; i++) {
print_binary_uc(*a);
printf(" ");
a++;
}
printf("\n");
}
void print_binary_uc(unsigned char value)
{
unsigned char value2;
int i;
int len = sizeof(unsigned char) * 8;

Assumes 8-bit characters. Look up CHAR_BIT in your reference.
for (i = len-1; i >= 0; i--)
{
value2 = value & ((unsigned char)1 << i);
printf("%d", value2 ? 1 : 0);
}
}


Remove del for email
 
B

Barry Schwarz

I haven't analyzed the bit pattern you provided, but the information you've
presented isn't consistent with "corruption".

Assume that the number is positive, but very small (let's say 10^(-30)).
Then no version of printf with a practical number of decimal places will
show anything but zero. Additionally, it would test as positive as you
indicated above.

In order to print this number, you'd to use the "%e" rather than the "%f"
format specifier.

Most binary scientific notation (i.e. float, double) formats contain a
binary exponent, which I suspect in this case is a very negative number.
The fact that there are a lot of "1"s set in the number are not inconsistent
with a very small positive number.

The number of '1"s set in the number has almost nothing to do with the
magnitude of the number. It only indicates how many *different*
powers of 2 are used to represent the number (or exponent).

Take a 32-bit integer that requires 15 "1"s. Convert it to a 64-bit
double. The non-exponent portion will still have 15 "1"s (one may be
implied). Divide this by a large power of 2 but avoiding underflow.
The quotient is now a very small non-zero value but the only change in
the result should be in the exponent. The 15 "1"s should still be
there and in the same positions.
Try "%e", and post your results ...


Remove del for email
 
B

Ben Bacarisse

Joe Wright said:
No Ben. There is only one value consistent with the 'bits' data as
presented.

The OP included code that produces it so the meaning of the byte
sequence is, indeed, unambiguous but IEEE floats are usually shown
the "other way round".
It is a 64-bit double on x86 architecture and is unique.

This particular value, expressed by 'printf(".16e", v)' is..

-1.7080703671901993e+39

..precisely.

This won't print as 0.000000 as reported. Of course the report may
have been wrong. Printing a double set to 4.273545594095197e-305
using the OP's code produces the output the OP gave. Your value is
same byte sequence but in reverse. My value matches all of the OP's
reported data.
 
J

Joe Wright

Ben said:
The OP included code that produces it so the meaning of the byte
sequence is, indeed, unambiguous but IEEE floats are usually shown
the "other way round".


This won't print as 0.000000 as reported. Of course the report may
have been wrong. Printing a double set to 4.273545594095197e-305
using the OP's code produces the output the OP gave. Your value is
same byte sequence but in reverse. My value matches all of the OP's
reported data.
Indeed.

00000000 10111110 00000010 10000110 00001001 00010100 00010100 11001000
Exp = 11 (-1011)
100 00001101
Man = .11110 00000010 10000110 00001001 00010100 00010100 11001000
4.2735455940951970e-305

Sorry.
 
K

Keith Thompson

Joe Wright said:
No Ben. There is only one value consistent with the 'bits' data as
presented. It is a 64-bit double on x86 architecture and is unique.

This particular value, expressed by 'printf(".16e", v)' is..

-1.7080703671901993e+39

..precisely.

Which would not appear as zero when printed with "%f".

The OP can easily figure this out using "%g" or "%e". The rest of us
can only guess what the OP actually means by the bit sequence he's
showing us (unless he also shows us the code for his "small function
to print the bits").
 
B

Ben Bacarisse

Keith Thompson said:
Which would not appear as zero when printed with "%f".

The OP can easily figure this out using "%g" or "%e". The rest of us
can only guess what the OP actually means by the bit sequence he's
showing us (unless he also shows us the code for his "small function
to print the bits").

He did. That is how I knew what the value was.
 
E

Ernie Wright

Ben said:
[...] 4.273545594095197e-305 [...] matches all of the OP's reported
data.

Not that it matters very much, but it only matches 7 of the 8 bytes.
The OP's 0x8A becomes 0x86 in your value. The value matching the OP's
bits is (approximately) 4.273554285789957e-305.

- Ernie http://home.comcast.net/~erniew
 
J

Joe Wright

Ernie said:
The exponent is -1012.

- Ernie http://home.comcast.net/~erniew

It depends on where you think the binary point is. Consider..

01000000 00010100 00000000 00000000 00000000 00000000 00000000 00000000
Exp = 1025 (3)
000 00000011
Man = .10100 00000000 00000000 00000000 00000000 00000000 00000000
5.0000000000000000e+00

In my view of things, the range of the exponent is 0..2047 and the bias
of the exponent is 1022.
 
D

Digital Puer

Ben said:
I think your bit pattern represents a number in the order of
4.3e-305. The %g format will print it as will (on my gcc) %.310f!


Thanks, everyone, for your help. When I printf with %.15e,
I get 4.273558636127927e-305. Looks like there is problem
with that variable somewhere else. I didn't know about the %e
and %g flags, so thanks for showing that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top