# ida decompiler output

``````double __cdecl sub_401660(float a1)
{
double v1; // st7@1
float v2; // ST00_4@1
float v4; // [sp+8h] [bp+4h]@1
float v5; // [sp+8h] [bp+4h]@1

v1 = a1;
LODWORD(v2) = 0x5F3759DF - (SLODWORD(a1) >> 1);
v4 = 0.5 * a1;
v5 = (1.5 - v4 * v2 * v2) * v2;
return (float)(v1 * v5);
}
``````

above function do some calculation using float number i am not able to understand LODWORD line

Regards

• `LODWORD` is the first 2 bytes of the `DWORD` and `HIDWORD` is the second 2 bytes of `DWORD`.. see those commands as just putting 2 pieces of a pizza pie together and then you read the whole pizza pie as a new number, and cast it to whatever datatype is suitable for it. I would just declare those macros in a new project and do some expirements with them both to understand their operation completely output a few `printf("%x\n", DWORDAnswer);` afterwards. (SLODWORD is signed version of LODWORD). Also you could replace all macro's with equivalent code to the macro to make it easier on the eye. Commented Dec 24, 2015 at 19:51

The `0x5F3759DF` constant seems familiar...

It is the fast inverse square root algorithm: http://en.wikipedia.org/wiki/Fast_inverse_square_root

comparing against that code `SLODWORD` and `LODWORD` would be a bit-preserving conversion to an integral type.

The last line does `a1*invsqrt(a1)` which is equal to `sqrt(a1) * (sqrt(a1)/sqrt(a1))` so it ends up calculating the square root of the input parameter.

I use this line as reference to understand the hidden macros'

http://www.wekk.net/files/defcon/defs.h

``````double __cdecl sub_401660(float a1)
{
double v1; // st7@1
float v2; // ST00_4@1
float v4; // [sp+8h] [bp+4h]@1
float v5; // [sp+8h] [bp+4h]@1

v1 = a1;
LODWORD(v2) = 0x5F3759DF - (SLODWORD(a1) >> 1);
v4 = 0.5 * a1;
v5 = (1.5 - v4 * v2 * v2) * v2;
return (float)(v1 * v5);
}
``````

could be simplified easier on the eyes like this

``````double __cdecl sub_401660(float a1)
{
double v1; // st7@1
float v2; // ST00_4@1
float v4; // [sp+8h] [bp+4h]@1
float v5; // [sp+8h] [bp+4h]@1

v1 = a1;
*((_DWORD*)&(v2)) = 0x5F3759DF - (*((long*)&(a1)) >> 1);
v4 = 0.5 * a1;
v5 = (1.5 - v4 * v2 * v2) * v2;
return (float)(v1 * v5);
}
``````

or how I would do it..

``````double __cdecl sub_401660(float a1)
{
double v1; // st7@1
float v2; // ST00_4@1
float v4; // [sp+8h] [bp+4h]@1
float v5; // [sp+8h] [bp+4h]@1

v1 = a1;
*((unsigned int *)&(v2)) = 0x5F3759DF - (*((long*)&(a1)) >> 1);
v4 = 0.5 * a1;
v5 = (1.5 - v4 * v2 * v2) * v2;
return (float)(v1 * v5);
}
``````

But this is how you do it if you are a hacker. Google.com search > 0x5F3759DF

``````float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;

x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed

return y;
}
``````
• The link to wekk.net is broken. Your macro for LODWORD works perfectly for me. I wonder if you have another macro for HIDWORD, and other similar macros. Commented Jan 26, 2022 at 10:22

SLODWORD(a1) returns the hex representation of a input read the `wiki-link` by ratchet freak and take a look at the poc below

``````#include <stdio.h>
#include <stdlib.h>
long dodance(float number){
float y  = number;
long i  = * ( long * ) &y;
return i;
}
void main (void) {
long a = dodance((float)3.2865);
printf("%08X\n%f\n",a,*(float *)&a);
}
``````

compile without optimization the above code using say

``````cl /Zi /EHsc /nologo /W4 /analyze *.cpp /link /RELEASE
``````

and execute the resulting binary

``````magicnum.exe
40525604
3.286500
``````

Compiling the enhanced code below you can see the maximum precision attainable by the 32 bit float is exhausted when the third term is evaluated in the series

``````#include <stdio.h>
#include <stdlib.h>
long dodance(float number)
{
float y  = number;
long i  = * ( long * ) &y;
return i;
}
int main (int argc , char *argv[])
{
if(argc != 3){printf ("usage %s <float> <int>\n",argv[0]);return 0;}
float input = (float) atof(argv[1]);
int term = atoi(argv[2]);
long a = dodance(input);
printf("%-10s= %08X\n%-10s= %f\n","hex",a,"float",*(float *)&a);
long b = (0x5f3759df - (a >> 1));
float c = *(float *)&b ;
printf("%-10s= %08X\n%-10s= %f\n","hex",b,"~1stfloat",c);
for(int i=0; i< term;i++)
{
c = (float)(c * ( 1.5 - ( (input * 0.5) * c * c )) );
printf("%-10s= %f\n","~nxtfloat",c);
}
return 1;
}
``````

result

``````magicnum.exe
usage magicnum.exe <float> <int>

magicnum.exe 3.2 1
hex       = 404CCCCD
float     = 3.200000
hex       = 3F10F379
~1stfloat = 0.566215
~nxtfloat = 0.558877

magicnum.exe 3.2 2
hex       = 404CCCCD
float     = 3.200000
hex       = 3F10F379
~1stfloat = 0.566215
~nxtfloat = 0.558877
~nxtfloat = 0.559017

magicnum.exe 3.2 3
hex       = 404CCCCD
float     = 3.200000
hex       = 3F10F379
~1stfloat = 0.566215
~nxtfloat = 0.558877
~nxtfloat = 0.559017
~nxtfloat = 0.559017 <-- no improvement over the previous result
``````

some theory

``````Newtons method is a proof and extension of binomial expansion theoram
for fractions and negative numbers
simplified binomial exapnsion for (1+x)^n = 1 + (n*x) + ((n*(n-1)/2)*x^2) + .......
we can derive an approximation of the  squareroot
sqrt(3.2)   = (4 - 0.8)^ 1/2
= 2 * ( 1 - 1/5) ^ 1/2
= 2 * ( 1 + 1/2*(-1/5)  + (-1/8) * (1/25) + .....)
= 2 * ( 1 - 1/10 - 1/200)
= 2 * ( 200/200 - 20/200 - 1/200)
= 2 * (179/200)
= 2 * (0.895)
= 1.79
1 / sqrt(3.2)   = 1 / 1.79
= 0.55865921787709497206703910614525
using calc.exe
3.2^-0.5    = 0.55901699437494742410229341718282
``````