Bitwise operators are faster. Avoid these micro-optimizations
TL;DR: Don't use bitwise operators unless your business model is bitwise logic.
- Improve readability
Some clever programmers solve problems we don't have.
We should optimize code based on evidence and use the scientific method.
We should benchmark only if necessary and improve code only if really necessary and bear the cost of changeability and maintainability.
const nowInSeconds = ~~(Date.now() / 1000)
const nowInSeconds = Math.floor(Date.now() / 1000)
We can tell our linters to warn us and manually check if it is worth the change.
- Real-time and mission-critical software.
- Premature Optimization
If we find this code in a pull request or code review, we need to understand the reasons. If they are not justified, we should do a rollback and change it to a normal logic.
Code Smell 20 - Premature Optimization
Maxi Contieri ⭐⭐⭐ ・ Nov 8 '20 ・ 2 min read
Code Smell 165 - Empty Exception Blocks
Maxi Contieri ⭐⭐⭐ ・ Sep 24 ・ 2 min read
Code Smell 06 - Too Clever Programmer
Maxi Contieri ⭐⭐⭐ ・ Oct 25 '20 ・ 2 min read
Code Smells are just my opinion.
Photo by Frédéric Barriol on Unsplash
Original Article Here.
Watch the little things; a small leak will sink a great ship.
Software Engineering Great Quotes
Maxi Contieri ⭐⭐⭐ ・ Dec 28 '20 ・ 13 min read
This article is part of the CodeSmell Series.
Oldest comments (29)
You can use the JS bitwise operator "OR" once -->
var x = y | 0this is much more efficient for computation, it do exactly as the Math.floor() function except you don't have to go trough the "Math" object and so on... (it is used in asm.js)
Hey but it’s clever and clever is not good in teams or in the world of corporate programming. Example; I’m 30ish and I’m now cognitively challenged due to my advanced age I need simple code if I’m in your team I don’t want the cost of going wtf StackOverflow, not seen this in my gosh dang whole career 😬😡
See it’s not worth it because time is money
I am over 50.
And I am tired of young people programming like in the 1960s.
Is this why you have this wonderful series? I have been keenly following.
If I’m not mistaken you can explain the GOTO statement 😁
of couse I can
Code Smell 100 - GoTo
Maxi Contieri ・ Nov 6 '21 ・ 2 min read
Please tell me your reasons to use the operator instead of the more declarative Math.foor ?
Do you have strong evidence this is really necessary ?
Relevant question is the same: Why it should be optimized?
Because computation on CPU can be slow...
I had a pixel art project, which enable one to draw on images and it does all the color blending computation in JS, which written in ASM.JS style is as much fast as it can be in webassembly, as I don't understand how I could make it work faster in WebGL...
ok. there are a few cases were you need to optimize the code.
There the 'Exceptions' in the article.
Most code does not need these optimizations
y | 0not necessarily equalling
y, and likewise
~~ynot necessarily equalling
Maxi Contieri ・ May 4 '21 ・ 2 min read
Numbers aren't double-precision floating-point values when one explicitely and systematically tells the compiler
| 0hey here is a integer
(x | 0)>>>0hey here is the same but positive, instead if our number is bigger than the maximum value of a 32 bits Unsigned integer, using
>>>0force the compiler to use, excuse me, "no doubles" for it. (in certain case ^^)
Not sure what you mean by "not what asmjs.org did". Numbers in JS are according to the JS spec, floating-point. Period. There is a BigInt type but that isn't involved in any way when applying bitwise ops to Numbers. If you are referring to what happens when one compiles C to JS, then whatever JS is produced isn't intended for human readability. The JS is essentially acting as a sort of machine code in that instance, and shouldn't be used as a baseline for writing JS that is intended for human readability.
The spec also defines the abstract operations
returning an integral number, i.e. it ceases to be an IEEE 754 floating point value but is just a signed or unsigned 32 bit string that is handled by the CPU's typical bitwise operations.
Int32(i.e. doesn't operate on them as IEEE 754 floating-point values).
PACKED_SMI_ELEMENTS(small integers, Int32; Element Kinds).
The main point is still the same: using a bitwise op as a clever trick to call the abstract ToInt32, when you don't really actually need the bitwise operation itself, only obfuscates your logic, negatively impacting readability and maintainability.
That is not a good reason to reject bitwise operations wholesale and much less a justification to stay ignorant about their semantics.
1b: mentally quick and resourceful but lacking in depth and soundness”
from: Webster's Ninth New Collegiate Dictionary (1983; ISBN 0919028667)
reflects that unsound thinking.
Int32with a range of -2147483648…2147483647 cannot cover the domain of values -8.64e12…8.64e12 that
(Date.now() / 1000)is capable of producing.
About bitwise operations
Andrea Giammarchi ・ Oct 8 '21 ・ 10 min read
Your explanation is fine if you need bitwise logic.
The sample from the code smell has nothing to do with bitwise logic.
I was primarily responding to:
which suggests that bitwise operators should be summarily banned from usage.
Ultimately bitwise operators do not operate on floating point numbers; the 32-bit bit strings they do operate on simply use the IEEE 754 binary64 as a conveyance.
There is an issue in TypeScript to add a
BitwiseInt32type to clearly differentiate that usage from
To me the sample code is indicative of a much bigger problem which is only tangentially related to bitwise operators; using code without fully understanding its limitations.
Aside from the readability issues, the statement that
Math.trunc(value)are equivalent is nonsense:
Math.trunc()works reliably without loss of precision over the range
However lots of interview preparation materials (e.g. Elements of Programming Interview in python) have plenty of exercises related to manipulating bit strings.
The article seems to unfairly single out bitwise operations when the actual issues are:
Using 2 bitwise complements as a means of calling ToInt32 a function that isn't otherwise directly exposed is sneaky. "Clever" lacks the negative connotation of "sneaky". So you are correct that it isn't clever. It is sneaky. Clever is just a nicer way of saying it.
@peerreynders the BitwiseInt32 proposal for TypeScript looks like a good way to add the missing semantics inherent in applying bitwise ops, not because you need bitwise logic, but because you are trying to utilize the side-effect of the op for type coercion.
Understanding bit manipulation, such as the article that you linked to on interview prep, can be very important. You'll notice that article is Python focused. I work with genetic algorithms a lot. Bit manipulation is extremely important. I mostly use Java for my GA work but occasionally Python, long ago C. Genetic algs is a case where bitwise ops are used because you need bitwise logic. In a GA, you aren't using a bitwise op to accomplish something else, such as the various ways they are used in JS for type coercion as a micro-optimization rather than just using a call to the more semantic trunc.
I think a title of Code Smell 180 - Micro Optimizations would have been more appropriate.
The whole idea of micro-optimizations is that they only really apply to code that has been proven to be on the hot path. From that perspective the sample code qualifies because under most circumstances using
Math.trunc()wouldn't be pessimizing prematurely.
Working with bit strings in 32-bit chunks isn't ideal but sometimes you gotta do what you gotta do.
indeed. I booked the title for another smell :)
Math.flooris not the same as
Math.truncis the equivalent
How to Find the Stinky Parts of Your Code ? shiva vashikaran mantra for love