Loading video...

Video Failed to Load

Go Home

I compiled Quake III's fast inverse square root on 64-bit Linux with gcc -O1 and it returned negative numbers. The long cast reads past the float into the stack, and the low bit of the return address ends up in the sign bit.

32,321 views • 9 days ago •via X (Twitter)

23 Comments

tetsuo's profile picture
tetsuo9 days ago

Quake III's Q_rsqrt as shipped, on 64-bit Linux. gcc -O1 q.c -o q && ./q gcc 13 prints -0.499154. clang 18 -O1 prints 0.000000, because reading 8 bytes from a 4-byte float is undefined behavior and clang compiles Q_rsqrt to a single ret. Your result depends on your compiler version.

Frederico Pissarra's profile picture
Frederico Pissarra9 days ago

x86-64 SysV ABI? If that is the case `long int` is 64 bits long, not 32... maybe this is the reason. Change `long int` to `int`.

tetsuo's profile picture
tetsuo9 days ago

Yep, that's the bug. On x86-64 SysV long is 8 bytes so *(long *)&y reads 4 bytes past y into the stack. The fix is at ~10:30 you went straight to the replies 😄

Frederico Pissarra's profile picture
Frederico Pissarra9 days ago

Yep... I've got straight to the replies (sorry!) and watched the video now... as said before, always an AMAZING analysis. I wish I had the patience and skills to do amazing videos like this one!

tetsuo's profile picture
tetsuo9 days ago

I'll jump on discord this weekend and give you my work flow.

Frederico Pissarra's profile picture
Frederico Pissarra9 days ago

As always, this is an AWESOME analysis...

Traveler's profile picture
Traveler8 days ago

Quake III was made in 1999. For 32-bit CPU. So kids, if you think using explicit types like uin32_t,uin64_t,int32_t,int64_t and co is just meaningless old farts fad then you are in a world of pain if you try porting shit from 1981 to 2002 or so (AMD Opteron in 2003 was first x86 compatible 64-bit CPU) to modern day.

X Girls's profile picture
X Girls9 days ago

woah 🤯

why's profile picture
why9 days ago

A perfect example of code that was “clever” on 32-bit and undefined on 64-bit. `long` being 8 bytes turns that type pun into an out-of-bounds read.

patrick mcqueeny's profile picture
patrick mcqueeny9 days ago

interesting! but why?

Andrew's profile picture
Andrew9 days ago

Ya ..W/e use like Java script or something

Wow Cool Thanks's profile picture
Wow Cool Thanks8 days ago

NOTHING ELSE MATTERS UNLESS STRAFE JUMP GIVES ME ACCELERATION.

MancerAI's profile picture
MancerAI8 days ago

I understand this is mostly out of curiosity, so maybe a stupid comment but; doesn't modern CPUs have fast inverse square root built in/as an OP

ai(Key)骆驼's profile picture
ai(Key)骆驼8 days ago

Good

ヴァルカン's profile picture
ヴァルカン8 days ago

how do you make these vids? cool

Ben's profile picture
Ben8 days ago

Yep that one also drove me nuts, genius math in the game.

Time's profile picture
Time8 days ago

てつお!元気?何言ってるのか全くわからない😊✨

Necati Demir, PhD's profile picture
Necati Demir, PhD8 days ago

Just curious. Did you generate this visualization with Opus 5.5? If so that looks great.

Pollino Geroni's profile picture
Pollino Geroni9 days ago

@grok sono ignorante a cosa servirebbe quello che l’Op ha fatto?

A. I. (Macro Photography)🔬's profile picture
A. I. (Macro Photography)🔬9 days ago

Magic.

Bill Crowell's profile picture
Bill Crowell8 days ago

Impressive. I wonder what the performance would be on an alternate function that uses division.

Charles Waters's profile picture
Charles Waters8 days ago

I thought that Quake's version of this code was intended to be fast and 'accurate enough' for the games use, but had known limitations and was probably 8 bit? Maybe 16? I wouldn't expect perfect performance from it.

Orion Night's profile picture
Orion Night9 days ago

many such cases. long is 8 bytes on LP64 so the cast reads 4 bytes past the float, straight into whatever junk the frame left there. the magic constant was never the problem, the type punning was

Related Videos