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?

0

3 Answers 3

6

Assuming 32-bit int and float,

unsigned int x;
std::stringstream ss;
ss << std::hex << "3F800000";
ss >> x;
return reinterpret_cast<float&>(x);
Sign up to request clarification or add additional context in comments.

7 Comments

@ardiyu07: "3F800000" is the binary representation "1.0" in IEEE-754's binary32. What the heck does "3F800000.24" mean?
This works, but it breaks strict aliasing: stackoverflow.com/questions/98650/…
@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 @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 - 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
|
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.

Comments

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);

2 Comments

Violating strict aliasing rules just as the other answer...
Modified answer as 1) did not work in my environment, but 2) union did work in my environment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.