I have the following function in a C program:
float invsqrt_32(float number) {
long int i; /* expected to be 32 bits */
float x2;
float y;
x2 = number * 0.5F;
i = * ( long int * ) &number;
i = 0x5f375a86 - ( i >> 1 );
y = * ( float * ) &i;
y *= ( 1.5F - ( x2 * y * y ) );
y *= ( 1.5F - ( x2 * y * y ) );
return (y * ( 1.5F - ( x2 * y * y ) )); }
It is adapted from here, with some improvements/adaptations made based on our needs and further studies.
With the input
number = 4.52949917e-06
after the magic number and bit-shif operation, on Visual Studio 2017 on Windows 10 (default compiler) I get
i = 1139498105
but in Eclipse 2021.09 on Ubuntu 18.04 (Linux gcc) I get
i = -3074621553247560583
I do not understand how this is happening.
What should I do to find the source of the difference?
CodePudding user response:
The issue is caused by using long int
type which is 64-bit long on 64-bit Linux while this type is 32-bit-long on 64-bit Windows. The type should be same length of IEEE 754 float
which is 32-bit long.
The proper solution should use int32_t
from stdint.h
but from comment it is indicated that the platform is not properly configured and int32_t
is actually 64-bit long.
The workaround is using int
rather than long int
which is 32-bit long on both Linux and Windows platforms.
float invsqrt_32(float number) {
int i; /* expected to be 32 bits */
float x2;
float y;
x2 = number * 0.5F;
i = * (int * ) &number;
i = 0x5f375a86 - ( i >> 1 );
y = * ( float * ) &i;
y *= ( 1.5F - ( x2 * y * y ) );
y *= ( 1.5F - ( x2 * y * y ) );
return (y * ( 1.5F - ( x2 * y * y ) )); }
Note, that the solution technically violates "strict aliasing rule" which forbids accessing object of type float
via a pointer to int
. To be fully compliant, the reinterpretation should be done by other means like cast by union.
union {
float f;
int i;
} u = { number };
i = u.i;