Velocity Reviews > printing bit representation of floats

# printing bit representation of floats

ben
Guest
Posts: n/a

 02-04-2005
i'm learning about the floating point format that's used on my computer
(apple mac so powerpc)

i've written a function to print out the bits in a float to see how
floats are represented and i also have a software programmer's
calculator called BinCalc which shows the bits of whatever number.

the bits that my code and the bits that the calculator show, for the
same value, don't match. for example for the number 1.0 my code says:
10111111_00000000_00000000_10000000

and the calculator says:
00111111_10000000_00000000_00000000

and for the value 1.6 my code prints:
10111111_11001101_11001100_11001100

and the calculator says:
00111111_11001100_11001100_11001101

the code that's used to print the float bits is below.

the first obvious difference is the left bit, the high order bit.
that's the bit that says if the value's negative or posative, the sign
bit right? so it really looks like there's something wrong with my code
becuase neither values in the above two examples are negative but both
print outs from my code has the left most bit set to 1. and you'd have
thought that the format that the software calculator is using would be
the same format that my computer's using, so the two representations
should tally i'd have thought. anyone know what's going on?

thanks, ben.

#include <stdio.h>

void bitfloatprint(float f)
{
unsigned bytes = sizeof(float); // number of bytes in a float
char bits; // number of bits to shift mask over by

while( bytes ) { // one loop per byte in the float (HO to LO)
for( bits = 7; bits >= 0; bits-- ) {
putchar(
( *((unsigned char *)&f + bytes) & 1 << bits ) == 0 ? '0' : '1'
);
// casting in above line so that +1 means plus
// one byte rather than plus one float
}
if( bytes != 1 )
putchar('_');
bytes--;
}
putchar('\n');
}

int main(void)
{
float f = 1.0;
bitfloatprint(f);
return 0;
}

ben
Guest
Posts: n/a

 02-04-2005
ahh! typical. sorry, forget this. sussed it just after i posted. the
main while loop wasn't going from HO byte to LO byte like it should
have been -- it was actually going the other way. so it should be:

#include <stdio.h>

void bitfloatprint(float f)
{
unsigned bytes = 0;
char bits;

while( bytes < sizeof(float) ) {
for( bits = 7; bits >= 0; bits-- ) {
putchar(
( (*((unsigned char *)&f + bytes)) & 1 << bits ) == 0 ? '0' : '1'
);
}
if( bytes != 3 )
putchar('_');
bytes++;
}
putchar('\n');
}

int main(void)
{
float f = 1.6;
bitfloatprint(f);
return 0;
}

Martin Ambuhl
Guest
Posts: n/a

 02-04-2005
ben wrote:
> i'm learning about the floating point format that's used on my computer
> (apple mac so powerpc)
>
> i've written a function to print out the bits in a float to see how
> floats are represented and i also have a software programmer's
> calculator called BinCalc which shows the bits of whatever number.
>
> the bits that my code and the bits that the calculator show, for the
> same value, don't match.

/* There is no reason to suppose that your calculator and your Apple
* have the same representation for floating point numbers. Try the
* following code out. Note that the output of my implementation is
* very different from what you report. */
#include <stdio.h>
#include <string.h>

#define showhex(x, s)\
{\
unsigned char c[sizeof x];\
size_t i;\
memcpy(c,&x,sizeof x);\
printf("%Lg (%s, size = %lu) as hex: \n%4s",\
(long double)x, s, \
(unsigned long) sizeof x, "");\
for (i = 0; i < sizeof x; i++)\
printf("%02x ", c[i]);\
printf("\n");\
}

int main(void)
{
long double xl;
double x;
float xf;
xf = x = xl = 1.0;
printf("[Output for this implementation]\n\n");
printf("For 1.0, Ben's program would yield in hex: "
"BF 00 00 80\n" "and his calculator: 3F 00 00 80\n");
showhex(xf, "float");
showhex(x, "double");
showhex(xl, "long double");
xf = x = xl = 1.6;
printf("\nFor 1.6, Ben's program would yield in hex: "
"BF CD CC CC\n" "and his calculator: 3F CC CC CD\n");
showhex(xf, "float");
showhex(x, "double");
showhex(xl, "long double");
return 0;
}

[Output for this implementation]

For 1.0, Ben's program would yield in hex: BF 00 00 80
and his calculator: 3F 00 00 80
1 (float, size = 4) as hex:
00 00 80 3f
1 (double, size = as hex:
00 00 00 00 00 00 f0 3f
1 (long double, size = 12) as hex:
00 00 00 00 00 00 00 80 ff 3f 00 00

For 1.6, Ben's program would yield in hex: BF CD CC CC
and his calculator: 3F CC CC CD
1.6 (float, size = 4) as hex:
cd cc cc 3f
1.6 (double, size = as hex:
9a 99 99 99 99 99 f9 3f
1.6 (long double, size = 12) as hex:
00 d0 cc cc cc cc cc cc ff 3f 00 00

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the

ben
Guest
Posts: n/a

 02-04-2005
In article <>, Martin Ambuhl
<> wrote:

> ben wrote:
> > i'm learning about the floating point format that's used on my computer
> > (apple mac so powerpc)
> >
> > i've written a function to print out the bits in a float to see how
> > floats are represented and i also have a software programmer's
> > calculator called BinCalc which shows the bits of whatever number.
> >
> > the bits that my code and the bits that the calculator show, for the
> > same value, don't match.

> /* There is no reason to suppose that your calculator and your Apple
> * have the same representation for floating point numbers. Try the
> * following code out. Note that the output of my implementation is
> * very different from what you report. */

Martin,

as you've probably seen, i made a mistake in the code and was correct
to assume that the softaware calculator's format is the same as the
computer's format (which does make sense as that calculator is designed
for programming on this computer, so you'd hope they'd be using the
same representation). here's the output from your code:

my output:
3f 80 00 00
3f f0 00 00 00 00 00 00
3f f0 00 00 00 00 00 00

3f cc cc cd
3f f9 99 99 99 99 99 9a
3f f9 99 99 99 99 99 9a

00 00 80 3f
00 00 00 00 00 00 f0 3f
00 00 00 00 00 00 00 80 ff 3f 00 00

cd cc cc 3f
9a 99 99 99 99 99 f9 3f
00 d0 cc cc cc cc cc cc ff 3f 00 00

(note the hex value you'd noted in the print statement for the value of
1.0 from my calculator: 3F 00 00 80 was slightly wrong. it was 3F 80 00
00 from the calculator)

the only difference between the float and double versions is endianess
-- mine big, yours little. but long double's pretty different to say
the least. i got this warning for that: warning: use of `long double'
type; its size may change in a future release. i'm using a slightly old
compiler (2002) so maybe that has changed by now. who knows.

thanks a lot, ben.

Michael Mair
Guest
Posts: n/a

 02-04-2005
ben wrote:
> In article <>, Martin Ambuhl
> <> wrote:
>
>
>>ben wrote:
>>
>>>i'm learning about the floating point format that's used on my computer
>>>(apple mac so powerpc)
>>>
>>>i've written a function to print out the bits in a float to see how
>>>floats are represented and i also have a software programmer's
>>>calculator called BinCalc which shows the bits of whatever number.
>>>
>>>the bits that my code and the bits that the calculator show, for the
>>>same value, don't match.

>
>
>>/* There is no reason to suppose that your calculator and your Apple
>> * have the same representation for floating point numbers. Try the
>> * following code out. Note that the output of my implementation is
>> * very different from what you report. */

>
>
> Martin,
>
> as you've probably seen, i made a mistake in the code and was correct
> to assume that the softaware calculator's format is the same as the
> computer's format (which does make sense as that calculator is designed
> for programming on this computer, so you'd hope they'd be using the
> same representation). here's the output from your code:
>
> my output:
> 3f 80 00 00
> 3f f0 00 00 00 00 00 00
> 3f f0 00 00 00 00 00 00
>
> 3f cc cc cd
> 3f f9 99 99 99 99 99 9a
> 3f f9 99 99 99 99 99 9a
>
> 00 00 80 3f
> 00 00 00 00 00 00 f0 3f
> 00 00 00 00 00 00 00 80 ff 3f 00 00
>
> cd cc cc 3f
> 9a 99 99 99 99 99 f9 3f
> 00 d0 cc cc cc cc cc cc ff 3f 00 00
>
> (note the hex value you'd noted in the print statement for the value of
> 1.0 from my calculator: 3F 00 00 80 was slightly wrong. it was 3F 80 00
> 00 from the calculator)
>
> the only difference between the float and double versions is endianess
> -- mine big, yours little. but long double's pretty different to say
> the least. i got this warning for that: warning: use of `long double'
> type; its size may change in a future release. i'm using a slightly old
> compiler (2002) so maybe that has changed by now. who knows.

Umh, have you actually run Martin's program on your machine?
Then the output should be the same.
That the representation of floating point types is (but for
endianness) the same across different machines is not at all
guaranteed!

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

Michael Mair
Guest
Posts: n/a

 02-04-2005
ben wrote:
> ahh! typical. sorry, forget this. sussed it just after i posted. the
> main while loop wasn't going from HO byte to LO byte like it should
> have been -- it was actually going the other way. so it should be:
>
>
> #include <stdio.h>
>
> void bitfloatprint(float f)
> {
> unsigned bytes = 0;
> char bits;

It is possible that char is an unsigned integer type, so you
should say explicitly that you want the signed flavour:
signed char bits;
Apart from that: bytes and bits both are loop counters for
you, having similar ranges. It makes not much sense to use
so much different types. Either use unsigned or signed int
for both or unsigned or signed char. For unsigned integer
loop variables, you would have to change the bits loop condition.
>
> while( bytes < sizeof(float) ) {

If you make this sizeof f, your code is essentially completely
independent of the type of f. This makes copy&paste errors
much less likely.
> for( bits = 7; bits >= 0; bits-- ) {

bits = CHAR_BIT-1;
for the portable variant.
Considering that you used a while outer loop, you may want
to look at
bits = CHAR_BIT;
while (bits-- != 0)
which works also for unsigned types.
> putchar(
> ( (*((unsigned char *)&f + bytes)) & 1 << bits ) == 0 ? '0' : '1'
> );

is
'0' + ( ( ((unsigned char *)&f)[bytes] & 1<<bits ) != 0 )

my preference would be rather to introduce an unsigned char *c
with c=&f and use this instead for any of the both ways or a
mixture.
> }
> if( bytes != 3 )
> putchar('_');
> bytes++;
> }
> putchar('\n');
> }
>
> int main(void)
> {
> float f = 1.6;
> bitfloatprint(f);
> return 0;
> }

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

ben
Guest
Posts: n/a

 02-04-2005
In article <>, Michael Mair
<> wrote:

> ben wrote:

> > my output:
> > 3f 80 00 00
> > 3f f0 00 00 00 00 00 00
> > 3f f0 00 00 00 00 00 00
> >
> > 3f cc cc cd
> > 3f f9 99 99 99 99 99 9a
> > 3f f9 99 99 99 99 99 9a
> >
> > 00 00 80 3f
> > 00 00 00 00 00 00 f0 3f
> > 00 00 00 00 00 00 00 80 ff 3f 00 00
> >
> > cd cc cc 3f
> > 9a 99 99 99 99 99 f9 3f
> > 00 d0 cc cc cc cc cc cc ff 3f 00 00

> Umh, have you actually run Martin's program on your machine?

yes i have. that's it there where it says my output.

Michael Mair
Guest
Posts: n/a

 02-04-2005
ben wrote:
> In article <>, Michael Mair
> <> wrote:
>
>
>>ben wrote:

>
>
>>>my output:
>>> 3f 80 00 00
>>> 3f f0 00 00 00 00 00 00
>>> 3f f0 00 00 00 00 00 00
>>>
>>> 3f cc cc cd
>>> 3f f9 99 99 99 99 99 9a
>>> 3f f9 99 99 99 99 99 9a
>>>
>>> 00 00 80 3f
>>> 00 00 00 00 00 00 f0 3f
>>> 00 00 00 00 00 00 00 80 ff 3f 00 00
>>>
>>> cd cc cc 3f
>>> 9a 99 99 99 99 99 f9 3f
>>> 00 d0 cc cc cc cc cc cc ff 3f 00 00

>
>
>>Umh, have you actually run Martin's program on your machine?

>
>
> yes i have. that's it there where it says my output.

Ok, so I misunderstood; from what you wrote I got the impression
that you are comparing the hex-output of your calculator with
Martin's original output instead of comparing the output of
your calculator, programm and Martin's programm...

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

ben
Guest
Posts: n/a

 02-04-2005
In article <>, Michael Mair
<> wrote:

> ben wrote:
> > ahh! typical. sorry, forget this. sussed it just after i posted. the
> > main while loop wasn't going from HO byte to LO byte like it should
> > have been -- it was actually going the other way. so it should be:
> >
> >
> > #include <stdio.h>
> >
> > void bitfloatprint(float f)
> > {
> > unsigned bytes = 0;
> > char bits;

>
> It is possible that char is an unsigned integer type, so you
> should say explicitly that you want the signed flavour:
> signed char bits;
> Apart from that: bytes and bits both are loop counters for
> you, having similar ranges. It makes not much sense to use
> so much different types. Either use unsigned or signed int
> for both or unsigned or signed char. For unsigned integer
> loop variables, you would have to change the bits loop condition.
> >
> > while( bytes < sizeof(float) ) {

> If you make this sizeof f, your code is essentially completely
> independent of the type of f. This makes copy&paste errors
> much less likely.
> > for( bits = 7; bits >= 0; bits-- ) {

> bits = CHAR_BIT-1;
> for the portable variant.
> Considering that you used a while outer loop, you may want
> to look at
> bits = CHAR_BIT;
> while (bits-- != 0)
> which works also for unsigned types.
> > putchar(
> > ( (*((unsigned char *)&f + bytes)) & 1 << bits ) == 0 ? '0' : '1'
> > );

>
> is
> '0' + ( ( ((unsigned char *)&f)[bytes] & 1<<bits ) != 0 )
>
> my preference would be rather to introduce an unsigned char *c
> with c=&f and use this instead for any of the both ways or a
> mixture.
> > }
> > if( bytes != 3 )
> > putchar('_');
> > bytes++;
> > }
> > putchar('\n');
> > }
> >
> > int main(void)
> > {
> > float f = 1.6;
> > bitfloatprint(f);
> > return 0;
> > }

ok thanks. not sure why i used byte size chunks and two loops. one's
got to be better than two.

#include <stdio.h>
#include <limits.h>

int main(void)
{
void bitfloatprint(float f);
float f;

f = 1.9;
bitfloatprint(f);
return 0;
}

void bitfloatprint(float f)
{
unsigned char bits = sizeof f * CHAR_BIT;

while( bits-- > 0 ) {
putchar( ( *((unsigned *) &f) >> bits & 1 ) + '0' );
if( !(bits % CHAR_BIT) && bits != 0 )
putchar('_');
}
putchar('\n');
}

ben
Guest
Posts: n/a

 02-04-2005
In article <040220052219500774%>, ben <> wrote:

> ok thanks. not sure why i used byte size chunks and two loops. one's
> got to be better than two.
>
>
> #include <stdio.h>
> #include <limits.h>
>
> int main(void)
> {
> void bitfloatprint(float f);
> float f;
>
> f = 1.9;
> bitfloatprint(f);
> return 0;
> }
>
> void bitfloatprint(float f)
> {
> unsigned char bits = sizeof f * CHAR_BIT;
>
> while( bits-- > 0 ) {
> putchar( ( *((unsigned *) &f) >> bits & 1 ) + '0' );
> if( !(bits % CHAR_BIT) && bits != 0 )
> putchar('_');
> }
> putchar('\n');
> }

ah, i've just thought, that won't work on little endian machines i
don't think. oh well, not to worry, that's enough on this i think.