-2

I'm just curious about this, and can't find anything on it. Is there a reason for it to use hexadecimal, or is it just because that was how it was originally written?

Code is below for reference.

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

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;
    i  = 0x5f3759df - ( i >> 1 );
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );
//  y  = y * ( threehalfs - ( x2 * y * y ) );

    return y;
}
  • 2
    Nuhhh, they're just showing off because they can. ;) – A. Abramov Aug 15 '15 at 08:42
  • 1
    possible duplicate of [John Carmack's Unusual Fast Inverse Square Root (Quake III)](http://stackoverflow.com/questions/1349542/john-carmacks-unusual-fast-inverse-square-root-quake-iii) – this Aug 15 '15 at 08:45
  • This, btw, is completely UB. There's a version around using a `union` instead, which is still UB, but makes it well-defined *as long as* the implementation really uses *IEEE-754* float representation. (It was probably used in *Q3* because it is often even faster than the `fsqrt` processor instruction, although less precise, and back then, this mattered. I'd consider it as mostly obsolete on today's computers, but, of course, still interesting) –  Aug 15 '15 at 08:45
  • Adding to my previous comment: *obsolete* for manual use of course. Some 3D hardware might use exactly this approach internally. –  Aug 15 '15 at 08:51
  • @this, not a duplicate, the question here is why did the programmer use a hex representation, not why did he use that number. – Ben Aug 15 '15 at 08:56
  • @Ben My mistake, the correct reason for closure is *primarily opinion-based*. You should close it for that reason. – this Aug 15 '15 at 08:58
  • 1
    @FelixPalmen The `union` trick is just as much UB under strict aliasing rules as the pointer punning. The only valid way to get at the bits of a float is to use `memcpy()`, or type punning to a `char*` because `char` types are exempted from strict aliasing rules. – cmaster - reinstate monica Aug 15 '15 at 08:59
  • @cmaster As I wrote, it is still UB, but using the `union` makes it explicit to the compiler that you're accessing the same location. So you're guaranteed the ordering, but the value is still undefined, because there is no guarantee about the memory layout of a `float` and an `int`. See for example [this question](http://stackoverflow.com/questions/11639947) Also note there's no *strict aliasing rule* term in the standard documents. –  Aug 15 '15 at 09:15
  • @FelixPalmen Even though the compiler could know about the two values being stored in the same place, the letter of the standard gives it full freedom to ignore that knowledge. It can reorder the write and the read, it can even simply call "undefined behavior" and optimize the whole function away. The `union` trick used to comply with the wording of the standard, but since C99 and strict aliasing rules, it doesn't. – cmaster - reinstate monica Aug 15 '15 at 10:37
  • @cmaster no it isn't, see answers in the question I linked. UB is *only* due to the fact there are no guaratees about representation, but you are guaranteed to access the same memory in the correct order. Of course, if you're reading an early version or even a draft, you will not find the relevant footnote. –  Aug 15 '15 at 10:40
  • @FelixPalmen You are right, I overlooked that footnote :-( – cmaster - reinstate monica Aug 15 '15 at 10:55

1 Answers1

5

There is no difference to the compiler between a number expressed as hex or as decimal. The reason for using hex is because it makes it easier for the programmer to understand.

In this case the programmer is manipulating bit-patterns in a floating point number, so the bit layout of the value is more important than its numerical value.

Since hex values map directly each character to four bits, it is the natural representation in this case.

For more on this particular function, the Fast Inverse Square Root, see here:

Ben
  • 34,935
  • 6
  • 74
  • 113
  • 2
    Notably, Carmack (usually, but wrongly, attributed) did *not* show off and use hex for the two floating point numbers elsewhere in the code. The constant itself is not meant as a float number. – Jongware Aug 15 '15 at 09:04
  • @Jongware, correct. 0x5f3759df is not a floating point number, it is a bit-pattern which is being used to in conjunction with the value y to generate a first estimate of the square root. – Ben Aug 15 '15 at 09:28