Note: This question started with a faulty premise: the values that appeared to be 0.0 were in fact very small numbers. But it morphed into a discussion of different ways of reinterpreting the bits of one type as a different type. TL;DR: until C++20 arrives with its new bit_cast
class, the standard, portable solution is memcpy
.
Update 3: here's a very short app that demonstrates the problem. The bits interpreted as float
always give a value of 0.0000:
#include <iostream>
int main() {
uint32_t i = 0x04501234; // arbitrary bits should be a valid float
uint32_t bitPattern;
uint32_t* ptr_to_uint = &bitPattern;
volatile float bitPatternAsFloat;
volatile float* ptr_to_float = &bitPatternAsFloat;
do {
bitPattern = i;
memcpy( (void*)ptr_to_float, (const void*)ptr_to_uint, 4 );
// The following 2 lines both print the float value as 0.00000
//printf( "bitPattern: %0X, bitPatternAsFloat: %0X, as float: %f \r\n", bitPattern, *(unsigned int*)&bitPatternAsFloat, bitPatternAsFloat );
printf( "bitPattern: %0X, bitPatternAsFloat: %0X, as float: %f \r\n", bitPattern, *(unsigned int*)&bitPatternAsFloat, *ptr_to_float );
i++;
} while( i < 0x04501254 );
return 0;
}
(original post)
float bitPatternAsFloat;
for (uint32_t i = 0; i <= 0xFFFFFFFF; i = (i & 0x7F800000) == 0 ? i | 0x00800000 : i + 1 )
{
bitPatternAsFloat = *(float*)&i;
...
The loop steps through every bit pattern, skipping those in which the float
exponent field is 0. Then I try to interpret the bits as a float
. The values of i
look OK (printed in hex), but bitPatternAsFloat
always comes back as 0.0. What's wrong?
Thinking that maybe i
is held in a register and thus &i
returns nothing, I tried copying i
to another uint32_t
variable first, but the result is the same.
I know I'm modifying the loop variable with the ternary in the for
statement, but as I understand it this is OK.
Update: after reading about aliasing, I tried this:
union FloatBits {
uint32_t uintVersion;
float floatVersion;
};
float bitPatternAsFloat;
// inside test method:
union FloatBits fb; // also tried it without the 'union' keyword
// inside test loop (i is a uint32_t incrementing through all values)
fb.uintVersion = i;
bitPatternAsFloat = fb.floatVersion;
When I print the values, fb.uintVersion
prints the expected value of i
, but fb.floatVersion
still prints as 0.000000. Am I close? What am I missing? The compiler is g++
6, which allows "type punning".
Update 2: here's my attempt at using memcpy
. It doesn't work (the float value is always 0.0):
uint32_t i = 0;
uint32_t bitPattern;
float bitPatternAsFloat;
uint32_t* ptr_to_uint = &bitPattern;
float* ptr_to_float = &bitPatternAsFloat;
do {
bitPattern = i; //incremented from 0x00000000 to 0xFFFFFFFF
memcpy( (void*)ptr_to_float, (const void*)ptr_to_uint, 4 );
// bitPatternAsFloat always reads as 0.0
...
i++;
} while( i );