DEV Community

Cover image for Math object: Dealing w/ Decimals and the '~~' Operator
colin-williams-dev
colin-williams-dev

Posted on

Math object: Dealing w/ Decimals and the '~~' Operator

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
Enter fullscreen mode Exit fullscreen mode

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?
Image description

Introducing: ~~ or the double-tilde operator.

console.log(~~13.12);           // --> 13

console.log(~~(-13.12));        // --> -13
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
;^]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:
Image description

Top comments (0)