0

I saw following code here.

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

I don't understand following line.

i  = * ( long * ) &y; 

Generally, we use * and & with pointer, but here both used with variable. So, what does it do here?

msc
  • 33,420
  • 29
  • 119
  • 214

3 Answers3

5

The line is taking a float, looking at the memory holding that float, reinterpreting that memory as memory holding a long, and getting that long. Basically, it's reinterpreting the bit-pattern of a floating point number as that of an integer, in order to mess around with its bits.

Unfortunately, that code is also wrong. You are not allowed to dereference that casted pointer, for reasons described here. In C, the one-and-only way of reinterpreting a bit pattern is through memcpy. (Depending on C variant and implementation, going through a union may be acceptable as well.)

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • Can you give a quick explanation on the major difference between a memcopy and doing the cast straight away (not through addressing)? – kabanus Dec 22 '17 at 20:06
  • @kabanus What do you mean by "doing the cast straight away"? – Sneftel Dec 22 '17 at 20:06
  • I mean `i=(long)y` – kabanus Dec 22 '17 at 20:07
  • 1
    @kabanus The difference is that in `(long)y`, a number is being converted. In the OP's case, a *memory address* is being converted. You're telling the compiler "you know that memory address? Pretend that the data there is an integer, not a float". Of course it isn't really, so the value you get out will be as much about how floating point numbers are represented as it is about what the number in question actually *was*. – Sneftel Dec 22 '17 at 20:10
  • Thanks, and I think that's worth to put in the answer. NM, I see this was closed :) – kabanus Dec 22 '17 at 20:14
  • I’m pretty sure the C standard still allows unions for type punning; I think it’s only C++ that prohibits them. – Daniel H Dec 22 '17 at 20:30
  • 1
    @DanielH C99 does, but C89 was cagey about it. – Sneftel Dec 22 '17 at 20:33
2

First, a disclaimer: This is technically undefined behavior because it violates the strict aliasing rule, but most compilers will do the below, and I don’t know what the standards situation was when this was first written.

When you look at the expression, there are four main parts:(

  1. y is the float variable we want to convert. Simple enough.
  2. & is the usual address-of operator, so &y is a pointer to y.
  3. (long *) is a cast to a pointer to long, so (long *) &y is a pointer-to-long pointing to the same location in memory as y is at. There is no real long there, just a float, but if both float and long are 32 bits (like the code assumes), this will give you a pointer to a long with the same bit pattern as a float.
  4. Finally, * dereferences the pointer. Thus, the full expression, * ( long * ) &y;, gives you a long with same bit pattern as y.

Usually, a long with the same bit pattern as a float would be useless, because they store numbers in completely different ways. However, it’s easier to do bit manipulation to a long, and the program later converts it back to a `float.

Daniel H
  • 7,223
  • 2
  • 26
  • 41
0

It means the address of y (making it a pointer) cast to a long pointer, dereferenced and assigned to i.

David Hoelzer
  • 15,862
  • 4
  • 48
  • 67
  • 1
    [There isn't really a spiral rule.](https://stackoverflow.com/questions/16260417/the-spiral-rule-about-declarations-when-is-it-in-error) There also isn't a spiral in this particular case. – Oliver Charlesworth Dec 22 '17 at 20:13
  • To clarify @OliverCharlesworth’s comment, the spiral rule is a simplification of the actual C++ type-parsing rules. Since it’s a simplification, there are a lot of cases where the spiral rule gives the wrong answer. In any case, it’s only for parsing types, not expressions. – Daniel H Dec 22 '17 at 23:42