Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's a proper way of type-punning a float to an int and vice-versa?

The code below performs a fast inverse square root operation by some bit hacks. The algorithm was probably developed by Silicon Graphics in early 1990's and it's appeared in Quake 3 too. more info

However I get the following warning from GCC C++ compiler: dereferencing type-punned pointer will break strict-aliasing rules

Should I use static_cast, reinterpret_cast or dynamic_cast instead in such situations?

float InverseSquareRoot(float x) {     float xhalf = 0.5f*x;     int32_t i = *(int32_t*)&x;     i = 0x5f3759df - (i>>1);     x = *(float*)&i;     x = x*(1.5f - xhalf*x*x);     return x; } 
like image 892
plasmacel Avatar asked Jul 22 '13 14:07

plasmacel


Video Answer


1 Answers

Forget casts. Use memcpy.

float xhalf = 0.5f*x; uint32_t i; assert(sizeof(x) == sizeof(i)); std::memcpy(&i, &x, sizeof(i)); i = 0x5f375a86 - (i>>1); std::memcpy(&x, &i, sizeof(i)); x = x*(1.5f - xhalf*x*x); return x; 

The original code tries to initialize the int32_t by first accessing the float object through an int32_t pointer, which is where the rules are broken. The C-style cast is equivalent to a reinterpret_cast, so changing it to reinterpret_cast would not make much difference.

The important difference when using memcpy is that the bytes are copied from the float into the int32_t, but the float object is never accessed through an int32_t lvalue, because memcpy takes pointers to void and its insides are "magical" and don't break the aliasing rules.

like image 109
R. Martinho Fernandes Avatar answered Sep 17 '22 18:09

R. Martinho Fernandes