1

I am trying to create a float from a hexadecimal representation I got from here. For the representation of 32.50002, the site shows the IEEE 754 hexadecimal representation as 0x42020005.

In my code, I have this: float f = 0x42020005;. However, when I print the value, I get 1.10E+9 instead of 32.50002. Why is this?

I am using Microsoft Visual C++ 2010.

Gareth
  • 3,502
  • 4
  • 20
  • 21

3 Answers3

5

When you assign a value to a float variable via =, you don’t assign its internal representation, you assign its value. 0x42020005 in decimal is 1107427333, and that’s the value you are assigning.

The underlying representation of a float cannot be retrieved in a platform independent way. However, making some assumptions (namely, that the float is in fact using IEEE 754 format), we can trick a bit:

float f;
uint32_t rep = 0x42020005;
std::memcpy(&f, &rep, sizeof f);

Will give the desired result.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    @0x499602D2 `intptr_t` is a type with the width of a pointer. That’s not at all what we want – we want a 32-bit type, independent of machine. `intptr_t`, on the other hand, can be a different size. – Konrad Rudolph Apr 02 '14 at 16:49
  • 2
    @KonradRudolph This is formally undefined behavior. The _intent_ of the standard is clearly that an implementation define it to give the expected results, but IIRC, g++ doesn't. (If you write something like `float f = 0.0; *reinterpret_cast(&f) = 0x42020005; std::cout << f;`, you might end up outputting 0.) The only way that is formally defined is using `memcpy`. (But I tend to use `reinterpret_cast` and/or `union` myself, depending on the compiler I'm targetting.) – James Kanze Apr 02 '14 at 17:01
  • @Kanze can you point at the section in standard where it says this? – berkus Apr 02 '14 at 17:40
  • @JamesKanze Ah, good catch. Personally I would only use `reinterpret_cast` when I can alias via `[unsigned] char*`, i.e. preserving strict aliasing (and yes, I could do that here, but it’s even more code). I’ve changed the answer. – Konrad Rudolph Apr 02 '14 at 22:17
2

0x42020005 actually is int value of 1107427333.

You can try out this code. Should work... Use union:

union IntFloat {
  uint32_t i;
  float f;
};

and call it when you need to convert the value.

union IntFloat val;
val.i = 0x42020005;
printf("%f\n", val.f);
rockinfresh
  • 2,068
  • 4
  • 28
  • 46
  • Cool, I've never had much use for union before. Thanks. – Gareth Apr 02 '14 at 16:56
  • 2
    Note that this is technically undefined behavior (although I don't know of a compiler where it won't work). – James Kanze Apr 02 '14 at 16:57
  • @James Are you confident that this will never break with optimisations turned on? After all, optimisers trace reads and writes and eliminate unused code paths – and this *does* come into conflict with strict aliasing violations. Are exceptions for unions built in? – Konrad Rudolph Apr 02 '14 at 16:59
  • @JamesKanze, I actually learn it from someone and have been using it since. I have tried it on Visual Studio 2008 to 2012, with no problem so far, of course, there are many methods like Konrad's method, a more standard approach actually. – rockinfresh Apr 02 '14 at 17:05
  • Them purpose of my method is to avoid assumption of big or little endian and to avoid breaking any aliasing rule. – rockinfresh Apr 02 '14 at 17:11
  • For more information on unions: http://stackoverflow.com/questions/2310483/purpose-of-unions-in-c-and-c – rockinfresh Apr 02 '14 at 17:12
  • 1
    @KonradRudolph G++ guarantees it explicitly. It will generally work _if_ all of the accesses to `union` are through the union members. If you do something like `float* pf = *val.f;`, and then access through `*pf`, it generally won't work. (This is probably why g++ chose to support this path, rather than the `reinterpret_cast`; it's rather simple to determine whether you're accessing through the `union`, without looking further, and avoid the dangerous optimizations.) – James Kanze Apr 02 '14 at 17:53
  • @KonradRudolph FWIW, however: although I think Microsoft supports it now, under roughly the same conditions as g++, some very, very early Microsoft C compilers didn't. – James Kanze Apr 02 '14 at 18:04
1

0x42020005 is an int with value of 1107427333.

float f = 0x42020005; is equal with float f = 1107427333;

tgmath
  • 12,813
  • 2
  • 16
  • 24