Math object: Dealing w/ Decimals and the '~~' Operator
colin-williams-dev
Posted on October 9, 2022
Today during some reading I stumbled onto an ongoing debate among the coding community: what is the fastest way to convert float (numbers with a decimal point) to an integer?
There are several different ways a programmer can handle this problem and I will go over a few of the simpler methods.
Speaking of methods, let's talk about the built-in Javascript object
Math
.
console.log(Math.ceil(4.20)); // --> 5
console.log(Math.floor(6.9)); // --> 6
console.log(Math.round(5.5)); // --> 6
console.log(Math.trunc(1.337));// --> 1
Let me break down the above example:
Math.ceil()
will round our float (decimal number) up to the next highest whole (integer) value. Think ceiling // above.Math.floor()
will round our float down to the next lowest whole number. Think floor // below.Math.round()
will use the most common arithmetic method of rounding up if decimal point is >= .5 or rounding down if <= .4.Math.trunc
or truncate will simply remove anything past the decimal point.
But what if there was another way? Another, arguably, faster way?
Introducing: ~~
or the double-tilde operator.
console.log(~~13.12); // --> 13
console.log(~~(-13.12)); // --> -13
The double-tilde operator behaves like a combination of our Math
methods. A positive number will be rounded down while a negative number will be rounded up. This can be useful in some cases because a method like Math.floor
may have undesired results when dealing with positive vs. negative numbers:
console.log(Math.floor(13.12)); // --> 13
console.log(Math.floor(-13.12));// --> -14
Above our positive number behaves as if it is rounded down while our negative number behaves almost as if it is rounded up (tricky because -14 is still "down" from -13)
Using ~~
is the equivalent of this function:
let doubleTilde = function(x) {
if(x < 0) return Math.ceil(x);
else return Math.floor(x);
}
doubleTilde = (x) => x < 0 ? Math.ceil(x) : Math.floor(x);
;^]
Applying the logic of Math.ceil
for negative numbers and Math.floor
for positive numbers.
Hope this can be of use to you! (in some very particular scenarios, but... oh well! happy coding!)
Lagniappe
~~
will coerce ANY datatype to a number and will also extract a number from a single-element array:
console.log(~~"acab"); // --> 0
console.log(~~NaN); // --> 0
console.log(~~null); // --> 0
console.log(~~undefined);// --> 0
console.log(~~[69]); // --> 69
Post-Script:
I didn't include every possible example but ~~ will even convert complex data types such as arrays ([]) and objects ({}) to a single number value (that value will === 0)...
It can even evaluate whole expressions or coerce the return value of a function to a single number value as well! Annnnnd, compared with Math.trunc
I would argue its superiority because Math.trunc
will return NaN for non-number / non-string data types. Try it in your code! <3
As I mentioned, Math.trunc versus bitwise operators is a contested debate among programmers and I encourage you to do your own reading/exploring/implementing of these ideas and find what works best for you. Here is a resource on bitwise operators and how the conversions/coercion with the double-tilde operator works... (it has to do with converting a decimal to a 32 bit/digit number which will remove all decimals anyway.. but that topic is far beyond my expertise):
https://stackoverflow.com/questions/38702724/math-floor-vs-math-trunc-javascript
And an image of the speed testing in the above link from user "Qwerty:
Posted on October 9, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.