user58389
user58389

Reputation: 213

Floating Point to Binary Value(C++)

I want to take a floating point number in C++, like 2.25125, and a int array filled with the binary value that is used to store the float in memory (IEEE 754).

So I could take a number, and end up with a int num[16] array with the binary value of the float: num[0] would be 1 num[1] would be 1 num[2] would be 0 num[3] would be 1 and so on...

Putting an int into an array isn't difficult, just the process of getting the binary value of a float is where I'm stuck. Can you just read the binary in the memory that the float variable? If not, how could I go about doing this in C++?

EDIT: The reason for doing the comparison this way is that I am wanting to learn to do bitwise operations in C++.

Upvotes: 21

Views: 52705

Answers (14)

Matthieu
Matthieu

Reputation: 3117

Using a template union and a static_assert allows conversion to/from both float and double:

template<typename F,typename I>
union _f2i {
    const F f;
    const I i;
    _f2i(F f) : f{f} { }
    _f2i(I i) : i{i} { }
    static_assert(sizeof(F) == sizeof(I), "Incompatible float/integer types");
};

Then you decide on float or double conversion:

//uint64_t test = f2i<double,uint32_t>{31.7}.i; // Assertion error at compile time

using f2i = _f2i<float,uint32_t>;
using d2i = _f2i<double,uint64_t>;

uint32_t intr = f2i{31.7f}.i;
float    fltr = f2i{uint32_t(0x41FD999A)}.f;
std::cout << std::hex << intr << std::endl;
std::cout << fltr << std::endl;

uint64_t lintr = d2i{31.7}.i;
double   dblr  = d2i{uint64_t(0x403FB33333333333)}.f;
std::cout << std::hex << lintr << std::endl;
std::cout << dblr << std::endl;

Gives:

41fd999a
31.7
403fb33333333333
31.7

Upvotes: 0

Meanwhaler
Meanwhaler

Reputation: 31

Here's my solution that doesn't give any warnings:

int32_t floatToIntBits(float f)
{
    char * c = (char*)&f;
    int32_t i = 0;
    i |= (int32_t)((c[3] << 24)     & 0xff000000);
    i |= (int32_t)((c[2] << 16)     & 0x00ff0000);
    i |= (int32_t)((c[1] << 8)      & 0x0000ff00);
    i |= (int32_t)((c[0])           & 0x000000ff);
    return i;
}

Upvotes: 0

nmd_07
nmd_07

Reputation: 706

You can do it with casting pointers as well. Here is a little example

#include <iostream>
#include <bitset>

using namespace std;

int main(){
    float f = 0.3f;
    int* p = (int*)&f;
    bitset<32> bits(*p);
    cout << bits << endl;
}

Upvotes: 1

Loki Astari
Loki Astari

Reputation: 264709

Use union and bitset:

#include <iostream>
#include <bitset>
#include <climits>

int main()
{
    union
    {
        float input; // assumes sizeof(float) == sizeof(int)
        int   output;
    } data;

    data.input = 2.25125;

    std::bitset<sizeof(float) * CHAR_BIT> bits(data.output);
    std::cout << bits << std::endl;

    // or
    std::cout << "BIT 4: " << bits[4] << std::endl;
    std::cout << "BIT 7: " << bits[7] << std::endl;
}

It may not be an array but you can access bits with [] operator as if you were using an array.

Output

$ ./bits
01000000000100000001010001111011
BIT 4: 1
BIT 7: 0

Upvotes: 33

codekaizen
codekaizen

Reputation: 27429

Can you just read the binary in the memory that the float variable?

Yes. Static cast a pointer to it to an int pointer and read the bits from the result. An IEEE 754 float type in C++ is 32 bits.

Upvotes: 3

test30
test30

Reputation: 3654

other approach, using stl

#include <iostream>
#include <bitset>

using namespace std;
int main()
{
    float f=4.5f;
    cout<<bitset<sizeof f*8>(*(long unsigned int*)(&f))<<endl;
    return 0;
}

Upvotes: 7

Jeremy Trifilo
Jeremy Trifilo

Reputation: 470

Well I don't believe C++ has any real safe way to store floats without some sort of issue. When it comes to moving between machines and is both efficient and easily stored without using a large storage capacity.

It's very accurate, but it won't support really insane values. You will be able to have up to 7 digits in any location, but you can't exceed 7 digits on either side. For the left you'll receive inaccurate results. On the right you'll get an error during read time. To resolve the error you can throw an error during the write or perform "buffer[idx++] & 0x7" on the read to prevent it from going outside 0 and 7 bounds. Keep in mind "& 0x7" only works because it's a power of 2 minus one. Which is 2^3 - 1. You can only do that with those values E.g. 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, etc...

So it's up to you if you want to use this or not. I felt it was a safe way to get most values you'll ever need. The example below shows how it's converted into a 4 byte array, but for C++ this would be a char*. If you don't want to perform division you can convert the POWERS_OF_TEN array into a secondary array with decimals and multiple instead.

const float CacheReader::POWERS_OF_TEN[] = 
{
    1.0F, 10.0F, 100.0F, 1000.0F, 10000.0F, 100000.0F, 1000000.0F, 10000000.0F
};

float CacheReader::readFloat(void)
{
    int flags = readUnsignedByte();
    int value = readUnsignedTriByte();
    if (flags & 0x1)
        value = -value;
    return value / POWERS_OF_TEN[(flags >> 1) & 0x7];
}

unsigned __int32 CacheReader::readUnsignedTriByte(void)
{
    return (readUnsignedByte() << 16) | (readUnsignedByte() << 8) | (readUnsignedByte());
}

unsigned __int8 CacheReader::readUnsignedByte(void)
{
    return buffer[reader_position] & 0xFF;
}

void CacheReader::writeFloat(float data)
{
    int exponent = -1;
    float ceiling = 0.0F;

    for ( ; ++exponent < 8; )
    {
        ceiling = (POWERS_OF_TEN[exponent] * data);
        if (ceiling == (int)ceiling)
            break;
    }

    exponent = exponent << 0x1;
    int ceil = (int)ceiling;
    if (ceil < 0)
    {
        exponent |= 0x1;
        ceil = -ceil;
    }
    buffer[writer_position++] = (signed __int16)(exponent);
    buffer[writer_position++] = (signed __int16)(ceil >> 16);
    buffer[writer_position++] = (signed __int16)(ceil >> 8);
    buffer[writer_position++] = (signed __int16)(ceil);
}

Upvotes: 0

Alexander Rafferty
Alexander Rafferty

Reputation: 6233

Easiest way:

float myfloat;
file.read((char*)(&myfloat),sizeof(float));

Upvotes: -1

Mehrdad Afshari
Mehrdad Afshari

Reputation: 422250

int fl = *(int*)&floatVar; //assuming sizeof(int) = sizeof(float)

int binaryRepresentation[sizeof(float) * 8];

for (int i = 0; i < sizeof(float) * 8; ++i)
    binaryRepresentation[i] = ((1 << i) & fl) != 0 ? 1 : 0;

Explanation

(1 << i) shifts the value 1, i bits to the left. The & operator computes the bitwise and of the operands.

The for loop runs once for each of the 32 bits in the float. Each time, i will be the number of the bit we want to extract the value from. We compute the bitwise and of the number and 1 << i:

Assume the number is: 1001011, and i = 2

1<<i will be equal to 0000100

  10001011
& 00000100
==========
  00000000

if i = 3 then:

  10001011
& 00001000
==========
  00001000

Basically, the result will be a number with ith bit set to the ith bit of the original number and all other bits are zero. The result will be either zero, which means the ith bit in the original number was zero or nonzero, which means the actual number had the ith bit equal to 1.

Upvotes: 15

Loki Astari
Loki Astari

Reputation: 264709

Looking at the comments in this answer (Floating Point to Binary Value(C++)) the reason to do this is to perform a bitwise comparison of two values.

#include <iostream>

int main()
{
    union Flip
    {
         float input;   // assumes sizeof(float) == sizeof(int)
         int   output;
    };

    Flip    data1;
    Flip    data2;
    Flip    data3;

    data1.input = 2.25125;
    data2.input = 2.25126;
    data3.input = 2.25125;

    bool    test12  = data1.output ^ data2.output;
    bool    test13  = data1.output ^ data3.output;
    bool    test23  = data2.output ^ data3.output;

    std::cout << "T1(" << test12 << ") T2(" << test13 << ") T3(" << test23 << ")\n";


}

Upvotes: 2

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 507373

You can use an unsigned char to read the float byte by byte into the integer array:

unsigned int bits[sizeof (float) * CHAR_BIT];
unsigned char const *c = static_cast<unsigned char const*>(
    static_cast<void const*>(&my_float)
);

for(size_t i = 0; i < sizeof(float) * CHAR_BIT; i++) {
    int bitnr = i % CHAR_BIT;
    bits[i] = (*c >> bitnr) & 1;
    if(bitnr == CHAR_BIT-1)
        c++;
}

// the bits are now stored in "bits". one bit in one integer.

By the way, if you just want to compare the bits (as you comment on another answer) use memcmp:

memcmp(&float1, &float2, sizeof (float));

Upvotes: 2

Noel Walters
Noel Walters

Reputation: 1853

Create a union of float and and unsigned long. set the value of the float member and iterate over the bits of the unsigned long value as already described in other answers.

This will eliminate the cast operators.

Upvotes: 1

Douglas Leeder
Douglas Leeder

Reputation: 53320

If you need a particular floating point representation, you'll have to build that up semantically from the float itself, not by bit-copying.

c0x standard: http://c0x.coding-guidelines.com/5.2.4.2.2.html doesn't define the format of floating point numbers.

Upvotes: 2

benjismith
benjismith

Reputation: 16735

Cast the int pointer to a float pointer, and you're done.

(Though I wouldn't declare it as an int array. I'd use void* to make it clear the the memory is being used as a dumping ground for other values.)

Incidentally, why don't you just use an array of floats?

Upvotes: 1

Related Questions