3

I have a string containing, for example "3F800000".

This is a hexadecimal representation of the float 1.0 Only I can't seem to find any convenient way of making this conversion in C++. Suggestions?

Unreasonable
  • 33
  • 1
  • 4

3 Answers3

6

Assuming 32-bit int and float,

unsigned int x;
std::stringstream ss;
ss << std::hex << "3F800000";
ss >> x;
return reinterpret_cast<float&>(x);
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • 2
    @ardiyu07: "3F800000" is the binary representation "1.0" in IEEE-754's `binary32`. What the heck does "3F800000.24" mean? – ephemient Feb 17 '11 at 17:04
  • 1
    This works, but it breaks strict aliasing: http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – Fred Larson Feb 17 '11 at 17:29
  • @ephemient C99 allows floating point hex, it allows a double to be represented without losing information (it came as a surprise to me aswell) – Martin Beckett Feb 17 '11 at 18:13
  • 1
    @Martin @ardiyu07: Floating-point hex is quite different from the bit-wise layout of IEEE 754. For example, "1.0" would simply be "0x1.0". – ephemient Feb 17 '11 at 18:15
  • @ephemient - true, I was just pointing out that "3F800000.24" is valid in C99, of course it has no similarity with the contents of a double in memory – Martin Beckett Feb 17 '11 at 18:58
  • @Martin: 3F800000.24 isn't a valid hex floating literal. 0x3F800000.24, on the other hand, is. – ephemient Feb 17 '11 at 19:32
  • @ephemient - doing embedded wire protocol stuff at the moment. So I'm seeing 0x in front of my eyes! – Martin Beckett Feb 17 '11 at 23:14
1

A newer variant, profiting from C++20 and std::bit_cast (#include <bit> for):

static_assert(sizeof(unsigned long) == sizeof(float));
// actually we don't need, std::bit_cast cares for as well
// as long as we let deduce the second template parameter
// from the function argument

auto bitPattern = std::strtoul("3F800000", nullptr, 16);
// or using std::stringstream, sscanf, whichever you prefer...

float value = std::bit_cast<float>(bitPattern);

In contrast to the other answers this is fully legal (not violating strict aliasing rules).

If C++20 is not available we still can use memcpy to legally copy the bit representation from the integral into the floating point variable (as done e.g. here), or, if we are willing to use C in parallel, use a union for type-punning, but this must occur in a C-source as it wouldn't be legal in C++ either.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
0

Another way to do this is:

int main() {
    std::string hexString = "3f9d70a4";
    auto long_val = std::stoul(hexString, nullptr, 16);
    cout << *reinterpret_cast<float *>(&long_val);
}

The above code may not work in some compile environments. The below code may work.

union U {
  uint64_t val;
  float f;
};
auto long_val = std::stoul(hexString, nullptr, 16);
U u = { long_val };
std::cout << u.f;

If the above code does not work in your compile environment, try memcpy

float f;
std::memcpy(&f, &long_val, sizeof f);
vijayst
  • 20,359
  • 18
  • 69
  • 113