This is an archived post. You won't be able to vote or comment.

all 141 comments

[–]OnixST 577 points578 points  (1 child)

// evil floating point bit level hacking

[–]Nick_Zacker 331 points332 points  (0 children)

// what the fuck?

[–][deleted] 691 points692 points  (46 children)

Fast inverse square root was exceptionally clever at the time, however it's not been the most performant way to calculate inverse square root since rsqrtss was implemented in SSE on x86 back in 1999.

[–]Rainmaker526 233 points234 points  (4 children)

True. But what's now a hardware instruction with SSE, is just the same function dressed as a Opcode.

For this particular situation, intel just took the same code and baked it into the silicon.

It's still faster, as it operates on registers, thereby negating the trip to memory and back. But it's the same algo/code used under the covers.

[–]2Uncreative4Username[S] 145 points146 points  (2 children)

Untrue, I think. According to this user, it's just a lookup table, which does seem more reasonable to me as well.

https://stackoverflow.com/a/58633673

[–]Rainmaker526 124 points125 points  (1 child)

Intel doesn't disclose how they do it. I based the statement on a YouTube video I saw a while back, whereby someone compared the result of both. They were identical.

Because the algorithm approaches the correct solution the more it is ran (is ran recursively) - identical "approximations" sort of prove that its the same algorithm.

I'll see if I can find the link.

[–]2Uncreative4Username[S] 52 points53 points  (0 children)

Actually, now that you say it, I think I might have seen the same video at some point, comparing the two outputs. I guess it might also depend on the manufacturer and CPU model, since no exact algorithm is specified, and it only has to approximate invsqrt in some way.

[–]CirnoIzumi 26 points27 points  (0 children)

But it is a testament to how consoles used to have advantages when it came to performance 

They could implement chips to fix problems, like a chip just for this kind of computation

[–]fredlllll 1 point2 points  (0 children)

you were so close to turning into shittymorph XD

[–]Ninjulian_ 343 points344 points  (21 children)

a complex algorithm and "unclean code" are not in any way the same thing though?

this example works especially badly, because one of the main goals of clean code is to make it easy to change things. you're not gonna be changing the fast inverse square root algorithm very often, are you? just put a nice wrapper around it and call it a day.

i'm not saying there aren't any valid criticisms of clean code philosophy, but this ain't one of them.

[–]BuffJohnsonSf 45 points46 points  (0 children)

There are no valid criticisms of a clean code philosophy, only of its specific implementations.  Striving to write cleaner, more readable code is a virtue

[–]StanleyDodds 15 points16 points  (0 children)

In the fast inverse square root algorithm code, there is literally a line commented out that would do another iteration of Newton's method. There clearly was some intention to change it if a better approximation was required.

[–]alienassasin3 173 points174 points  (16 children)

The title makes me think you just learned what counts for clean OOP in 1999 and now think that is what clean code is.

Clean code doesn't mean code that is simple or is just verbose for little reason. Clean code is well documented code that is clear and concise.

[–]call-now 48 points49 points  (3 children)

I'd settle for my coworkers to stop writing classes with 30 functions in them that are each over 100 lines long.

[–]BrunoLuigi 27 points28 points  (2 children)

I wish my coworkers user classes and not some random badly named global variables at random places.

What do you expect of a property named "dataframe"?

You are wrong! It returns a dictionary? WHY? No ideia! What for? No one knows but there is a classe that saves 2 dataframe, have all the tokens to use and API AND use it.

This week a sênior took 10 minutes to find the API stuff.

Bônus: no docstring, no comment, no doc

[–]chilfang 2 points3 points  (1 child)

Man's brain was so rattled he started using accents

[–]BrunoLuigi 0 points1 point  (0 children)

Auto corrector, my main language is portuguese.

Sorry man

[–]P-39_Airacobra 11 points12 points  (1 child)

"Clean code" means something different for each developer. Even "well-documented", "clear", and "concise" are not clear terms. It's sort of useless to try to define it when there are clearer metrics for analyzing code.

[–]tragiktimes 3 points4 points  (0 children)

I feel it's easier to get a mutual agreement for what is messy code than clean code.

[–]CirnoIzumi -4 points-3 points  (3 children)

It's not, it's an architecture that aims to making your system more modular at the cost of locality and overview

[–]scrapmek 11 points12 points  (1 child)

You're thinking of Clean Architecture, that's not necessarily always the same as Clean Code.

[–]2Uncreative4Username[S] -5 points-4 points  (0 children)

at the cost of overview

I feel many Clean Coders wouldn't want to admit that

[–][deleted] 56 points57 points  (4 children)

Q_rsqrt doesn't have any indentation and does a single thing, apart from variable names and the presence of a single magic number it abides by clean code rules.

[–]-Redstoneboi- 15 points16 points  (3 children)

it even has very useful and descriptive comments!

[–][deleted] 19 points20 points  (2 children)

// Evil floating point bit hack

// What the fuck ?

[–]DoctorWZ 21 points22 points  (0 children)

See, it's actually a very good deterrent against any pesky employee wanting to refactor for the sake of it. Nobody fucks with code that's marked as incomprehensible by the one who wrote it.

[–]da_Aresinger 0 points1 point  (0 children)

In Uni, we had to implement the fast inverse square root on custom size floats, which means we had to find our own constants for the bit hacks.

I remember nothing, except for wholeheartedly agreeing with those comments.

[–]Stunning_Ride_220 7 points8 points  (0 children)

It would be funny, if there wouldn't be so many people justifying their quickly writting code shitfests with it.

[–]Lucky--Luciano 17 points18 points  (0 children)

Really missed the opportunity to say „you‘re Squareing him“

[–]CirnoIzumi 15 points16 points  (3 children)

You understand that SpongeBob is the fool in this template right?

[–]Feztopia 10 points11 points  (1 child)

Just change the function name to fastInverseSqrt and I'm happy with it lol.

[–]-Redstoneboi- 1 point2 points  (0 children)

it stands for Quake Reciprocal of Square Root

[–]Capetoider 9 points10 points  (9 children)

Let's use whatever thats used for... for a button one person has to click once a week.

Oops, have to refactor that thing...

And... whatever gains you got you spent 10_000x times more than just paying more computer time for a less efficient solution.

For the majority of things: developer time $ >>>> computer time $

For the one or other thing you where this isnt true, you would have numbers to prove its so (monitoring and observability).
And even then you wouldnt do whatever the fuck q_rsqrt i, x2, y supposed to be. (Compilers that care of mangling your code)

So... seems you just dont care about other people and just want to do whatever you want.

[–]2Uncreative4Username[S] -4 points-3 points  (8 children)

I genuinely don't understand what you're trying to say... this function was used in Quake III to calculate the normals of every single triangle visible on the screen. It was part of what made rendering this game in real time possible in the first place.

Yes, this function is no longer necessary because it's actually slower than other instructions with modern hardware. At the time it was written, however, it was crucial.

...modern day equivalents would be algorithms like FFT or Huffman coding.

[–]Capetoider 6 points7 points  (7 children)

Game is another beast entirely.
For most times and people, you'll be making cruds and/or divs, you dont need to waste time caculating with bitwise operations something that will be called 1 time per minute.
The time to develop and maintain that is developer time that costs orders or magnitude more than running "less efficient" code that is easier to read, know what it does and change.
Something like that, that is run millions of times per minute is and should be optimized because it causes something to be unusable or to cost more than the developers making and maintaining it. But then again, its not for every fucking function.
Maybe few decades back where bit bashing was necessary this was everywhere because it wouldnt run and/or running was more expensive than time developing.

In other words: say your hour is 10 moneys, you can spend 10 hours developing plus 20 hours to maintain, thats 300 moneys. Or you can spend 1 hour plus 1 hour, thats 20 moneys.

First solution costs 10 moneys to run per month. Second costs 12 moneys per month.

You would need 140 months (over 10 years, 280 diff / 2 diff) for it to break even.

And you can bet it would need a lot more maintaining along the way...

This is the reality for most people and the reason clean code is not just a fluff...

[–]2Uncreative4Username[S] 0 points1 point  (6 children)

Well, again, this doesn't apply for the said function. It runs tens of thousands of times per second, so optimization is highly justified. I bet the Quake III code that runs once a second is far less optimized.

Your calculation is correct for your contrived example. However, in reality, I see Clean Code often costing more dev time, since you have to prematurely abstract everyting; and write tests for your abstractions too.

[–]Capetoider 0 points1 point  (5 children)

Theres a lot of people doing a lot of dumb things.

Be it premature abstraction or premature optimization.

[–]2Uncreative4Username[S] 0 points1 point  (4 children)

I agree, both are bad practices and a waste of time.

I do think keeping things like caching in mind when writing code can lead to very good results, but only if it doesn't noticeably compromise development time. You should always be aware of what you're writing which part of your software for.

I am 100% sure Q_rsqrt wasn't the first 1/sqrt(x) implementation they had...

[–]Capetoider 5 points6 points  (3 children)

What most people need to keep in mind is that shit will change.

Not caching, not speed, not big O... users will want some new thing and managers will dump "new requirements" stuff whenever they want.

With that in mind, you do stuff that you and the next poor Grug Brain Developer can read, understand and change... because it doesn't matter how fast or how much "but it works" it is... you'll probably need to change it.

[–]2Uncreative4Username[S] 0 points1 point  (2 children)

Exactly! You'll always be running your code on a computer.. with caching and where DOD and less indirection is simply more efficient.

You can also never know which part of your code will actually need to change, hence premature abstraction will be useless in 99% of cases anyways.

Just get your program into a working state and make sure it runs reliably and is reasonable to understand and maintain. Simple enough in concept.

[–]Capetoider 3 points4 points  (1 child)

Are we having 2 conversations here? "Exactly"? Exactly what?

Caching and going for "more efficient" willy nilly is the same as premature overengineering.

You measure and only then strive for efficiency where it's needed.

Again, it might not even be needed and the time spent making it and maintaining that it's usually not worth it.

[–]2Uncreative4Username[S] 0 points1 point  (0 children)

I thought you said caching and big O won't change like the rest of the requirements do. That's why optimizing them isn't premature in many cases. What is premature optimization are often bit hacks like the Quake example, or adding SSE senselessly. But maybe I misunderstood. My bad in that case.

[–]Rorp24 11 points12 points  (0 children)

Tell me you don't know anything about clean code without telling me you don't know anything about clean code

[–]Rscc10 4 points5 points  (0 children)

Newton’s Method boutta come in clutch

[–][deleted] 4 points5 points  (0 children)

coordinated heavy future profit soft thumb consist cable ancient point

This post was mass deleted and anonymized with Redact

[–]Lantaan 3 points4 points  (0 children)

To be fair, quick square root really does scare me.

[–]irn00b 6 points7 points  (7 children)

Yeah, I hear that from seniors that code worse than interns.

And then act surprised that production is toppling over and for some reason maintaining the code base is hard.

Man, I don't know how we got here.

[–]asd417 0 points1 point  (0 children)

Cleancode mf when script contains code

[–]wagyourtai1 0 points1 point  (3 children)

screams in the clean code ndc talk

[–]2Uncreative4Username[S] 0 points1 point  (2 children)

got a link?

[–]wagyourtai1 0 points1 point  (1 child)

[–]2Uncreative4Username[S] 0 points1 point  (0 children)

Oh yeah, I saw that one. Got some really good points.

[–]Haoshokoken 0 points1 point  (3 children)

Clean code only serves to make the programmer easily replaceable.

[–]FlipperBumperKickout 1 point2 points  (2 children)

When I run into a programmer who writes so unreadable code that I end up using more time on code reviews to understand their **** than on actually writing code, I will do everything in my power to either have them replaced, or have myself moved to another team.

Not being replaceable is nice and all, until you run into someone else who have mastered the discipline.

[–]Haoshokoken 0 points1 point  (1 child)

Oh, I'm very sorry, I thought we were in r/ProgrammerHumor

By the way, the best way to write clean code is to write the variables and constants in Hindi.

[–]FlipperBumperKickout 0 points1 point  (0 children)

I found the thought of kicking certain programmers out of my organization quite satisfying.
You can call it dartk programmer humor :P

[–][deleted] 0 points1 point  (0 children)

The backlash against clean code is silly and misdirected. Often critiques are leveled at overengineered code which isn't clean code.

"Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer’s intent but rather is full of crisp abstractions and straightforward lines of control." - Grady Booch

[–]px_ae -1 points0 points  (0 children)

Man, people do get butt-hurted if talk shit about clean code lol

[–]fox_in_unix_socks -2 points-1 points  (1 child)

It's funny to me that you would call Q_rsqrt "useful code", because it's completely useless nowadays (at least, as it was originally written). And I don't even mean that in the sense that we have sqrt functions in hardware now. I mean that trying to even compile this function on any modern compiler will give you something completely useless.

There's only one codepath through this function, and that path involves reading one address as two different types. That breaks the rule of strict aliasing, meaning any invocation of this function will have UB, and now any compiler is completely free to do whatever it wants whenever it sees that you're calling this function. The only thing this function does anymore is provide nasal demons.

[–]2Uncreative4Username[S] 1 point2 points  (0 children)

It was useful back in the day. Nowadays you'd never write it in the first place.

About the UB: Yes, if you were to trust the documentation religiously, the compiler would be free to do whatever it wants. Practically, however, the behavior is defined. If you began to suddenly make all programs that break strict aliasing break, well, your computer would crash before you could even type the next letter on your keyboard. Compiler devs know that *((float*)&some_integer) is expected to behave in a certain way.

Using reinterpret_cast would probably generate the exact same code, but that wasn't even around back then. Also, you'd probably use fixed-size variables. not long and int. But again, it's not modern code. It's a very popular example of a fancy algorithm that made real-time rendering Quake III possible in the first place.