601

I'm seeing this in some code, and I have no idea what it does:

var jdn = function(y, m, d) {
  var tmp = (m <= 2 ? -1 : 0);
  return ~~((1461 * (y + 4800 + tmp)) / 4) + 
         ~~((367 * (m - 2 - 12 * tmp)) / 12) - 
         ~~((3 * ((y + 4900 + tmp) / 100)) / 4) + 
         d - 2483620;
};

What's the ~~ operator do?

Drew Noakes
  • 266,361
  • 143
  • 616
  • 705
jismo
  • 6,021
  • 3
  • 13
  • 4
  • 3
    You've probably figured it out by now but it returns the number of days between the millennium and a given date – Awalias Apr 11 '13 at 10:52
  • 14
    Google'd this when I saw it on codewars, only to find out google doesn't support tildes. Thank you Duck Duck Go! – Jim Jones Jan 13 '14 at 04:00
  • 1
    in simple words, it converts '9' into a number 9. And its must faster than Math.floor() even with IE8 if you do the following in console: typeof ~~'9'//number – STEEL Mar 03 '14 at 06:55
  • Hey Spencer, what did you use to search on DuckDuckGo for this? I just tried https://duckduckgo.com/?q=coffeescript+~ and it didn't give good results – Dinis Cruz Dec 05 '14 at 02:15
  • 1
    Not having comments is one thing but what I hate most is that someone named this `jdn`. I don't even know what that stands for. – Andy Feb 16 '15 at 06:47
  • This should be considered: https://www.youtube.com/watch?v=65-RbBwZQdU – AturSams Apr 17 '17 at 08:56
  • tl;dr Because of constant propagation and loop invariance, people often get the wrong impression of what's fast. – AturSams Apr 17 '17 at 09:02
  • 3
    Math.trunc(), not Math.floor() – Xitalogy Jun 08 '17 at 22:17
  • 1
    @JimJones - I don't know about back in 2014, but here in the future, you'll be pleased to hear that Google now accepts tilde's. (That's how I got here) [https://www.google.com/search?q=js+"~~"](https://www.google.com/search?q=js+"~~") :-) – ashleedawg Aug 22 '20 at 14:08

4 Answers4

774

That ~~ is a double NOT bitwise operator.

It is used as a faster substitute for Math.floor() for positive numbers. It does not return the same result as Math.floor() for negative numbers, as it just chops off the part after the decimal (see other answers for examples of this).

RealHandy
  • 374
  • 2
  • 6
  • 22
ghoppe
  • 19,804
  • 3
  • 26
  • 20
  • +1 Was not aware that it floored the value, but I guess it makes sense. (However aren't bitwise operators slower in JavaScript than arithmetic operators making this a slower method?) – Chad May 11 '11 at 23:24
  • 310
    @ghoppe: Worth noting that it differs from `.floor()` in that it actually just removes anything to the right of the decimal. This makes a difference when used against a negative number. Also, it will always return a number, and will never give you `NaN`. If it can't be converted to a number, you'll get `0`. – RightSaidFred May 11 '11 at 23:27
  • @Chad - It's probably still faster than `Math.floor()`, which has to look up the Math global object *and* do a function call. – jismo May 11 '11 at 23:28
  • 1
    The test that the article links to has `Math.floor` in the title of the text, but `Math.round` in the code, so that doesn't say anything about the speed of `Math.floor`... – Guffa May 11 '11 at 23:38
  • 2
    @Guffa It's a good thing that test page is editable then. :) I just tested it and `~~` was twice as fast as `Math.floor` on Safari 5. – ghoppe May 11 '11 at 23:44
  • 20
    @ghoppe: Yes, the two not operations are actually faster than the single floor method. They run in about 0.2 microseconds instead of 0.5 microseconds when I test it in Firefox on my computer. That means that you need to use it a lot before it's noticable. In a functon like the one in the OP it's just micro optimisation, and only makes the code harder to follow. – Guffa May 11 '11 at 23:51
  • 1
    @guffa It depends. If it's a function for updating an interface element, every microsecond counts. If it's a function used for on-the-fly validation, for example, I'd want the form to feel as responsive as possible. – ghoppe May 12 '11 at 00:13
  • 1
    @ghoppe: The screen updates at best 100 times a second, so you would have to use the function something in the order of 10000 times before it's even possible to see the difference. – Guffa May 12 '11 at 05:35
  • 2
    @Guffa What does screen update rate have to do with the speed of doing calculations? Someone could be using this inside for loops or on mouse events. – Shane Reustle Sep 20 '11 at 15:51
  • 1
    @Shane Reustle: Read the comments above to follow the discussion. – Guffa Sep 20 '11 at 21:38
  • 30
    I ran into an integer overflow issue using this technique with very large numbers (the result of dividing numbers from the Navigation Timing API by 62 during base-62 encoding). For instance, in Firefox, Chrome and IE, ~~(2419354838.709677) == -1875612458, whereas Math.floor(2419354838.709677) == 2419354838. – Jacob Wan Jul 12 '12 at 22:08
  • 1
    @RightSaidFred Probably worth an edit to the answer, yeah? – ruffin Aug 21 '12 at 13:55
  • 8
    DON'T USE ~~! In IE10, it's 8 times slower than doing other bitwise operations for the same thing! Better use zero right shift (>>0), it's the fastest one, and looks more similar to signed-to-unsigned conversion (>>>0). – Triang3l Dec 21 '12 at 14:20
  • 1
    @JacobWan Yes, this isn't a browser-dependent matter. Bitwise operations in JS produce signed 32-bit integers, so this should be avoided if there's any chance that the input is greater than 2^31 - 1. – JLRishe Apr 11 '14 at 13:18
  • 8
    Similar to Math.trunc(), but not Math.floor() – Xitalogy Jun 08 '17 at 22:21
  • Wrong! It looks like the code example has been through a minifier. It is being used to save space. ~~ is shorter than Math.floor() – Quentin 2 Sep 07 '18 at 07:40
  • 4
    While ~~ is faster alias of Math.floor(), -~ is an alias of Math.ceil() – Junaid Anwar Oct 18 '18 at 04:28
  • Thanks @JunaidAnwar, had the doubt – Abax May 12 '20 at 08:22
  • It looks like for negative numbers you just switch it around: `-~` becomes `Math.floor()` and `~~` becomes `Math.ceil()`. And here I thought `~~` was just for parsing integer strings... – omikes Dec 30 '20 at 05:35
188

It hides the intention of the code.

It's two single tilde operators, so it does a bitwise complement (bitwise not) twice. The operations take out each other, so the only remaining effect is the conversion that is done before the first operator is applied, i.e. converting the value to an integer number.

Some use it as a faster alternative to Math.floor, but the speed difference is not that dramatic, and in most cases it's just micro optimisation. Unless you have a piece of code that really needs to be optimised, you should use code that descibes what it does instead of code that uses a side effect of a non-operation.

Update 2011-08:

With optimisation of the JavaScript engine in browsers, the performance for operators and functions change. With current browsers, using ~~ instead of Math.floor is somewhat faster in some browsers, and not faster at all in some browsers. If you really need that extra bit of performance, you would need to write different optimised code for each browser.

See: tilde vs floor

Community
  • 1
  • 1
Guffa
  • 640,220
  • 96
  • 678
  • 956
  • 107
    +1 for "it hides the intention of the code", i wasted 10 minutes to know what `~~` does. Anyway I also have to admit it's already strong in me the dark side that's already tempting me to use `~~` in place of `Math.floor` forever in my new code now on. :)))) – Marco Demaio Feb 04 '12 at 12:16
  • 2
    Note that micro tests like JSPerf (necessarily) run the test code enough times that on-the-fly runtime optimizations (such as in V8) kick in. That test shows that (if used very heavily) `Math.floor()` _can_ be as fast as `~~` on Chrome, but not that it _is always_ the same speed. These days it's just quite hard to say for sure whether or not one bit of code is "faster" than another (accounting for different browsers and invocation scenarios). – Phrogz May 31 '12 at 21:47
  • 1
    Why on earth is Chrome 22 so much slower than Chrome 8?? – Matt Sach Jan 08 '13 at 14:23
  • @MattSach: The figures are only comparable if tested on the same computer, or if plenty enough people have tested it. Chrome has so many versions that there is rarely more than a handful of persons that has tested the code with each version. – Guffa Jan 08 '13 at 14:31
  • 4
    Just remember that Math.floor() exists for a reason. Don't go off using ~~ because it's 2 microseconds faster than Math.floor if you don't understand where it might cause overflows or other unexpected results. – dudewad Jan 23 '14 at 18:10
  • This gap has narrowed significantly for Chrome. https://jsperf.com/math-floor-vs-math-round-vs-parseint/183 – Graham P Heath Jan 22 '16 at 23:19
  • As mentioned in other comments here, it's not the same as Math.floor. – rdm Feb 24 '20 at 21:36
140
~(5.5)   // => -6
~(-6)    // => 5
~~5.5    // => 5  (same as Math.floor(5.5))
~~(-5.5) // => -5 (NOT the same as Math.floor(-5.5), which would give -6 )

For more info, see:

bowsersenior
  • 12,000
  • 2
  • 44
  • 51
  • 10
    `~(-5.5)` => `4`, `~(4)` => `-5`, `~~(-5.5)` => `-5`. Therefor, not the same as `Math.floor` – zzzzBov Aug 22 '11 at 18:51
  • @zzzzBov, I updated the post to clarify that `~~` is not the same as `Math.floor()` for negative numbers. – bowsersenior Aug 25 '11 at 15:42
  • Math.floor(-5.5), which would give -6. Bcos Math.floor will return largest integer less than or equal to a given number. Math.floor(-5.00000001) also give -6. – SridharKritha Jun 06 '18 at 11:38
22

The diffrence is very simple:

Long version

If you want to have better readability, use Math.floor. But if you want to minimize it, use tilde ~~.

There are a lot of sources on the internet saying Math.floor is faster, but sometimes ~~. I would not recommend you think about speed because it is not going to be noticed when running the code. Maybe in tests etc, but no human can see a diffrence here. What would be faster is to use ~~ for a faster load time.

Short version

~~ is shorter/takes less space. Math.floor improves the readability. Sometimes tilde is faster, sometimes Math.floor is faster, but it is not noticeable.

Community
  • 1
  • 1
Jason Stackhouse
  • 1,558
  • 2
  • 14
  • 19