-1
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

  • 1
    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. – SSpoke Dec 24 '15 at 19:51
5

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.

0

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 
0

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

Find this link http://gostash.it/en/stashes/184

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;
} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.