686

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
  • 300,895
  • 165
  • 679
  • 742
jismo
  • 6,871
  • 3
  • 15
  • 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
  • 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
  • 4
    Math.trunc(), not Math.floor() – Xitalogy Jun 08 '17 at 22:17

4 Answers4

900

That ~~ is a double Bitwise NOT 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).

ghoppe
  • 21,452
  • 3
  • 30
  • 21
  • +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
  • 331
    @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
  • 35
    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
    @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
  • 11
    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
  • 6
    While ~~ is faster alias of Math.floor(), -~ is an alias of Math.ceil() – Junaid Anwar Oct 18 '18 at 04:28
  • 1
    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
  • `~~` is the equivalent of `parseInt` – ffletcherr May 10 '22 at 06:59
221

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
  • 687,336
  • 108
  • 737
  • 1,005
  • 134
    +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
  • 8
    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
  • If anyone is wondering why there is a single operation of converting it to an integer. Here you go https://stackoverflow.com/questions/1723575/how-to-perform-a-bitwise-operation-on-floating-point-numbers#:~:text=Floating%20point%20numbers%20don't,apply%20bitwise%20operations%20to%20them. – kooskoos Apr 19 '23 at 09:58
173
~(5.5)   // => -6
~(-6)    // => 5
~~5.5    // => 5  (same as Math.trunc(5.5) and Math.floor(5.5))
~~(-5.5) // => -5 (same as Math.trunc(-5.5) but NOT the same as Math.floor(-5.5), which would give -6 )

For more info, see:

bowsersenior
  • 12,524
  • 2
  • 46
  • 52
  • 14
    `~(-5.5)` => `4`, `~(4)` => `-5`, `~~(-5.5)` => `-5`. Therefor, not the same as `Math.floor` – zzzzBov Aug 22 '11 at 18:51
  • 1
    @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
25

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,796
  • 2
  • 18
  • 19