xotix
xotix

Reputation: 520

Bit representation of float using an int pointer

I have the following exercise:

Implement a function void float to bits(float x) which prints the bit representation of x. Hint: Casting a float to an int truncates the fractional part, but no information is lost casting a float pointer to an int pointer.

Now, I know that a float is represented by a sign-bit, some bits for its mantissa, some bits for the basis and some bits for the exponent. It depends on my system how many bits are used.

The problem we are facing here is that our number basically has two parts. Let's consider 8.7 the bit representation of this number would be (to my understanding) the following: 1000.0111

Now, float's are stored wit a leading zero, so 8.8 would become 0.88*10^1

So I somehow have to get all the information out of my memory. I don't really see how I should do that. What should that hint hint me to? What's the difference between a integer pointer and a float pointer?

Currently I have this:

void float_to_bits() {
    float a = 4.2345678f;
    int* b;
    b = (int*)(&a);
    *b = a;

    std::cout << *(b) << "\n";
}

But I really don't get the bigger picture behind the hint here. How do I get the mantissa, the exponent, the sign and the basis? I also tried playing around with the bit-wise operators >>, <<. But I just don't see how this should help me here, since they won't change the pointers position. It's useful to get e.g. the bit representation of an integer but that's about it, no idea what use it'd be here.

Upvotes: 0

Views: 1598

Answers (2)

Tomer W
Tomer W

Reputation: 3433

The hint directs you how to pass the Float into an Integer without passing through value conversion.
When you assign floating-point value to an integer, the processor removes the fraction part. int i = (int) 4.502f; will result in i=4;

but when you make a int pointer (int*) point to a float's location, no conversion is made, also when you read the int* value.

to show the representation, i like seeing HEX numbers,
thats why my first example was given in HEX
(each Hexa-decimal digit represents 4 binary digits).

but it is also possible to print as binary,
and there are many ways (I like this one best!)

Follows an annotated example code:
Also available @ Culio

#include <iostream>
#include <bitset>
using namespace std;

int main()
{
   float a = 4.2345678f; // allocate space for a float. Call it 'a' and put the floating point value of `4.2345678f` in it.
    unsigned int* b; // allocate a space for a pointer (address), call the space b, (hint to compiler, this will point to integer number)
    b = (unsigned int*)(&a); // GREAT, exactly what you needed! take the float 'a', get it's address '&'.
    //                          by default, it is an address pointing at float (float*) , so you correctly cast it to (int*).
    //                          Bottom line: Set 'b' to the address of a, but treat this address of an int!

    // The Hint implied that this wont cause type conversion:
    // int someInt = a; // would cause `someInt = 4` same is your line below:
    // *b = a; // <<<< this was your error.
    // 1st thing, it aint required, as 'b' already pointing to `a` address, hence has it's value.
    // 2nd by this, you set the value pointed by `b` to 'a' (including conversion to int = 4);
    // the value in 'a' actually changes too by this instruction.

    cout << a << " in binary " << bitset<32>(*b)  << endl;
    cout << "Sign    " << bitset<1>(*b >> 31) << endl; // 1 bit (31)
    cout << "Exp     " << bitset<8>(*b >> 23) << endl; // 8 bits (23-30)
    cout << "Mantisa " << bitset<23>(*b) << endl; // 23 bits (0-22)
}

Upvotes: 2

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 153792

The hint your teacher gave is misleading: casting pointer between different types is at best implementation defined. However, memcpy(...)ing an object to a suutably sized array if unsigned char is defined. The content if the resulting array can then be decomposed into bits. Here is a quick hack to represent the bits using hexadecimal values:

#include <iostream>
#include <iomanip>
#include <cstring>

int main() {
    float f = 8.7;
    unsigned char bytes[sizeof(float)];
    std::memcpy(bytes, &f, sizeof(float));
    std::cout << std::hex << std::setfill(‘0’);
    for (int b: bytes) {
        std::cout << std::setw(2) << b;
    }
    std::cout << ‘\n’;
}

Note that IEEE 754 binary floating points do not store the full significand (the standard doesn’t use mantissa as a term) except for denormalized values: the 32 bit floats store

  • 1 bit for the sign
  • 8 bits for the exponent
  • 23 bits for the normalized significand with the non-zero high bit being implied

Upvotes: 4

Related Questions