How do you output binary representation of floats?
I am new to programming, I've done web development, but I am currently trying to learn real programming. The question I have is already answered here.
union ufloat {
float f;
unsigned u
};
ufloat u1;
u1.f = 0.3f;
What I don't get is how it works. What does the 0.3
part d开发者_开发技巧o? I couldn't find it in my text. And how does this convert a float to binary? Because cout<<u1.u;
doesn't seem to give me the answer. Can someone help?
0.3
is just a test value. Printing u1.u
will not give you the binary representation, but the value of the binary representation interpreted as a base 10 integer. To get the binary value, you have to convert u1.u
to binary.
Another way you can do the conversion is by using bitwise operators.
For example:
unsigned x = 11;
do
{
cout << (x & 1); // print last bit
x = x >> 1; // get rid of the printed bit
} while ( x );
Note that this will print the bits in reverse order (least significant first). I'll leave it up to you to fix this (you can use recursion or store values in an array and then print the array reversed).
I also suggest you read about unions. Basically, the unsigned
will occupy the same memory space as the float
, allowing you to circumvent the restrictions of using bitwise operators to find the binary representation of the float
.
The answers lies in how unions work in C/C++. A union allows you to represent multiple types of data using the same space in memory. So in your example, the ufloat
union stores the float and the integer in the same memory space. Depending on how you access this memory space, (either via the f
data member or the u
data member), the program will interpret the memory region as either a float or an unsigned integer respectively.
When you access the memory region via the u
data member, the program thinks you want to represent the memory region as a binary integer, rather than a floating point value. But since the memory region is actually storing a floating point value (0.3f), it simply outputs this value as if it was a binary integer. Thus, you get your binary representation of the float.
To be excessively pedantic, that's not valid C or C++.
I suspect that every compiler in existence supports it, but as far as the standard is concerned, it's not valid to write one member of a union and then read another. However, to even know that float
and unsigned
are the same size you're already using some implementation-defined information, so you may as well use more. It's common and it generally works.
For reference, though, you can always examine memory as a series of bytes:
#include <iostream>
#include <iomanip>
#include <climits>
#include <cassert>
int main() {
float f = 0.3;
unsigned char *buf = (unsigned char*)(&f);
// Now we just have to print the sucker.
assert(CHAR_BIT == 8); // otherwise hex isn't much use
// This shows the byte representation, low addresses on the left.
// On a little-endian machine, you might like to count down for
// convenience of reading.
for (int i = 0; i < sizeof f; ++i) {
std::cout << std::hex << std::setw(2) << std::setfill('0');
std::cout << static_cast<unsigned int>(buf[i]) << ' ';
}
std::cout << '\n';
}
Output (on my machine):
9a 99 99 3e
If you do prefer to use unsigned
rather than unsigned char
:
#include <cstring>
float f = 0.3;
unsigned u;
assert(sizeof f == sizeof u);
std::memcpy(&u, &f, sizeof f);
std::cout << std::hex << u << "\n";
Output (on my machine):
3e99999a
精彩评论