Home > Blockchain >  Fast Inverse Sqrt() [from Quake3 source code] works in Visual Studio, but not Eclipse?
Fast Inverse Sqrt() [from Quake3 source code] works in Visual Studio, but not Eclipse?

Time:12-02

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;
  •  Tags:  
  • c
  • Related