0

When I try to convert a float to an unsigned char array and then back to a float, I'm not getting the original float value. Even when I look at the bits of the float array, I'm seeing a bunch of different bits set than what were set originally.

Here is an example that I made in a Qt Console application project.

Edit: My original code below contains some mistakes that were pointed out in the comments, but I wanted to make my intent clear so that it doesn't confuse future visitors who visit this question.

I was basically trying to shift the bits and OR them back into a single float, but I forgot the shifting part. Plus, I now don't think you can do bitwise operations on floats. That is kind of hacky anyway. I also thought the std::bitset constructor took in more types in C++11, but I don't think that's true, so it was implicitly being cast. Finally, I should've been using reinterpret_cast instead when trying to cast to my new float.

#include <QCoreApplication>
#include <iostream>
#include <bitset>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    const float f = 3.2;
    unsigned char b[sizeof(float)];
    memcpy(b, &f, sizeof(f));
    const float newF = static_cast<float>(b[0] | b[1] | b[2] | b[3]);

    std::cout << "Original float: " << f << std::endl;
    // I expect "newF" to have the same value as "f"
    std::cout << "New float: " << newF << std::endl;
    std::cout << "bitset of original float:     " << std::bitset<32>(f) << std::endl;
    std::cout << "bitset of combined new float: " << std::bitset<32>(newF) << std::endl;
    std::cout << "bitset of each float bit:     " << std::endl;
    std::cout << "                       b[0]:  " << std::bitset<8>(b[0]) << std::endl;
    std::cout << "                       b[1]:  " << std::bitset<8>(b[1]) << std::endl;
    std::cout << "                       b[2]:  " << std::bitset<8>(b[2]) << std::endl;
    std::cout << "                       b[3]:  " << std::bitset<8>(b[3]) << std::endl;

    return a.exec();
}

Here is the output from the code above:

Original float: 3.2
New float: 205
bitset of original float:     00000000000000000000000000000011
bitset of combined new float: 00000000000000000000000011001101
bitset of each float bit:
                       b[0]:  11001101
                       b[1]:  11001100
                       b[2]:  01001100
                       b[3]:  01000000
Programmer_D
  • 601
  • 2
  • 15
  • 27
  • If you're wanting to get the original value back out, you'd (essentially) need to cast your `unsigned char*` to a `float*` and dereference it. – Kevin Feb 16 '17 at 20:59
  • You will lose precision when going from floating point to text representation then back to floating point. Best practice is to keep everything in floating point and convert to text format when outputting to the User. – Thomas Matthews Feb 16 '17 at 21:06
  • 1
    I guess you misunderstand all of: bitset constructor, `|` operator, and `static_cast`. Check documentation or test out those operations individually (using output statements) to compare your expectations with results – M.M Feb 16 '17 at 21:07
  • Why are you ORing a bunch of characters together?! – David Schwartz Feb 16 '17 at 21:16
  • related/dupe: http://stackoverflow.com/questions/3991478/building-a-32bit-float-out-of-its-4-composite-bytes-c – NathanOliver Feb 16 '17 at 21:16
  • @M.M @David Schwartz I believe I correctly used the bitset constructor. Could you please tell me how I used it incorrectly? Also, I didn't realize that using bitwise concatenation was really bad here. Could you guys explain why it's bad/how I'm not using it correctly? And yes, I probably should've used reinterpret_cast instead, but that wouldn't have worked anyway in this case. Seems like `memcpy` is the way to go! – Programmer_D Feb 17 '17 at 00:51
  • `|` does not mean "bitwise concatenation". Look at the output of `bitset<32>(f)`. Does that match what you expected? Try `f = 3.3;` instead of 3.2, and see if `bitset<32>(f)` changes. – M.M Feb 17 '17 at 01:55
  • @M.M I now see my mistakes and edited the question so that people know what I was trying to do. Now I understand what you were saying. – Programmer_D Feb 18 '17 at 19:31

1 Answers1

3

A previous answer and comment that has been deleted (not sure why) led me to use memcpy.

const float f = 3.2;
unsigned char b[sizeof(float)];
memcpy(b, &f, sizeof(f));
float newF = 0.0;
memcpy(&newF, b, sizeof(float));
Programmer_D
  • 601
  • 2
  • 15
  • 27