3 ms·
He posts c code and says that it computes the inverse square root, but the code he posted is undefined c, so while it could compute the inverse square root of i
by casey2 2y ago
He posts c code and says that it computes the inverse square root, but the code he posted is undefined c, so while it could compute the inverse square root of it's input it could also do a long list of other stuff.
One of the many reasons you should stay away from real world languages when talking about algorithms unless you are an expert in the language.
- tadfisher 2y agoThe code he posted is straight from the Quake 3 source release, a program which has certainly been installed and used on hundreds on millions of real computers. UB pedantry makes no difference to the actual behavior of the program as demonstrated.
- wizzwizz4 2y agoIf we're talking real-world languages, the code is perfectly well-defined. It's undefined behaviour in Abstract C, the C of the Specification, which to my knowledge nobody has ever implemented, but Quake 3 was not written in Abstract C. It was written in Visual C++ 2003, gcc 2.95, and some other specific C implementation. The code snippet that the article claims is C: int32_t compute_magic(void) { double sigma = 0.0450465; double expression = 1.5 * pow(2.0, 23.0) * (127.0 - sigma); int32_t i = expression; return i; } which, as far as I can tell, is perfectly well-defined Abstract C.
- deleted 2y ago[deleted]
- TillE 2y agoSpecifically, I think the original code will always do what you expect as long as sizeof(long) == sizeof(float), and the alignment is the same. In reality no compiler is gonna do weird stuff unless your hardware target is weird.
- kragen 2y agocompiler engineers have been disappointing our 'surely no compiler would ever be so perverse as to do x' expectations for 25 years now, and it doesn't seem that they're likely to stop soon
- btdmaster 2y agoExamples of such a weird hardware target include Linux and MacOS, which use LP64: https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_m... If you use a union, your code won't read or write out of bounds, since it will save space for the larger type. Ideally you would also specify _Float32_t and int32_t for some pseudoportability (at least before endianness gets involved), although I'm aware this was not available in 1999.
- cgrealy 2y agoMinor correction: Q3 came out in 99, so it was probably written in either VC++ 97 or VC6. Otherwise, carry on.
- dahart 2y agoIt’s a historical artifact being presented in its original form. There’s no reason this code can’t be updated with a more modern bitwise int-float conversion. Do that if you want to use it. Whether it is bad practice or not, people used to do this all the time, and so the compilers all tend to support type conversion via pointer and type punning via union. A lot of critical code in the real world would break if it suddenly didn’t work. C++ bit-cast is brand new (C++20) and until now the suggestion in C++ was to use memcpy, and hope and pray it gets elided. That might be correct but boy is it ugly and gross.