What Does Bitwise NOT Actually Do to a Number?
Bitwise NOT flips every bit in an integer, then the language interprets that new bit pattern as a number again. That’s why ~5 often turns into -6 in two’s-complement systems. If you want to see the transformation without squinting at binary, try our free NOT calculator.
What bitwise NOT actually means
The NOT operator is usually written as ~ in languages like JavaScript, C, C++, and Java. It is not arithmetic negation, and it does not mean “make this negative.” It works one layer lower: it inverts each bit in the value’s binary representation.
If a bit is 0, it becomes 1. If it is 1, it becomes 0. On fixed-width integers, that means the entire pattern changes, and the result depends on how the language stores signed numbers.
Think of it as flipping a row of switches, not subtracting from zero.
This is why bitwise operators feel strange at first. You are not asking the computer to do math in base 10. You are asking it to manipulate the raw bits, then reinterpret the result as a signed or unsigned integer.
Why ~5 becomes -6
Most modern systems use two’s complement for signed integers. In that representation, flipping all the bits and adding one gives you the negative form of a number. The neat shortcut is that ~x becomes -(x + 1).
That identity is the whole trick. It is not magic, and it is not specific to one language. It follows directly from how two’s-complement integers are encoded.
So the common examples line up like this:
~0 = -1~1 = -2~5 = -6
If you have seen this before and thought the operator was “negate plus one,” the truth is reversed. The bit flip happens first. The numeric meaning comes after.
Binary width matters more than people expect
Bitwise NOT only makes sense in a system with a defined bit width. Eight bits, 32 bits, 64 bits, whatever the machine or language chooses — there has to be a boundary somewhere. Otherwise “flip every bit” would be an infinite mess of leading ones and zeros.
That boundary is why a value can look different depending on where you run it. In many languages, integer operations are carried out in 32-bit signed form, even if the original value came from a wider number type. JavaScript is a classic example: bitwise operators coerce numbers into 32-bit signed integers before they do the work.
That coercion can be surprising. A floating-point value like 12.9 gets truncated before the bits are flipped. So if you expected a precise decimal operation, bitwise NOT will happily ignore that expectation and keep going.
For a broader primer on how these operators fit together, our guide on what bitwise operations are and when you would actually use them covers the bigger picture.
How languages handle bitwise NOT differently
The operator looks the same in many languages, but the surrounding rules change the result. C and C++ tend to follow the target integer type closely. JavaScript first converts the value to a signed 32-bit integer, which often catches people off guard.
Here is the basic shape of it in JavaScript:
console.log(~0); // -1
console.log(~1); // -2
console.log(~5); // -6
console.log(~12.9); // -13, because 12.9 becomes 12 firstThat last line is the trap. The decimal part disappears before the operator runs. If you are debugging code and the result looks wrong, check whether the language is silently narrowing or truncating the value first.
Unsigned integers add another wrinkle. If you flip all the bits in an unsigned 8-bit value, the result stays in that 8-bit range, so ~0x05 becomes 0xFA. Same bit flip, different interpretation.
Where bitwise NOT is actually useful
Bitwise NOT is not something most application code needs every day. It shows up more in systems work, data encoding, masks, and low-level fiddling. When it does appear, it is usually part of a bitmask rather than a standalone stunt.
A common pattern is to invert a mask before applying it. Say you want to clear a flag while leaving the rest untouched. You can flip the mask with ~ and then combine it with &.
const READ = 0b0001;
const WRITE = 0b0010;
const EXEC = 0b0100;
let perms = READ | WRITE | EXEC; // 0b0111
perms = perms & ~WRITE; // clear the WRITE bit
// result: 0b0101That pattern is everywhere in flag-based APIs. Think permissions, feature bits, packed status values, and protocol fields. The operator is small, but the effect is surgical.
A worked example
Let’s walk through a concrete example with a 4-bit view, just to make the inversion obvious. Real machines use wider integers, but the idea is easier to see with a tiny bit pattern.
Number: 5
Binary: 0101
Flip bits: 1010
Interpreted as signed 4-bit two's complement:
1010 = -6That signed interpretation is the part people miss. The raw bits 1010 are not inherently “minus six.” They only become -6 when you read them in a two’s-complement signed system.
You can test the same pattern in code with a wider integer:
const n = 5;
const flipped = ~n;
console.log(n); // 5
console.log(flipped); // -6
console.log(flipped.toString(2)); // binary representation in JavaScript's signed 32-bit modelIf you want to inspect the conversion across bases, pairing this with a binary or number-base tool helps. The point is not just what the operator returns, but how the result is encoded underneath.
Why it can be a debugging headache
Bitwise NOT becomes confusing when you mix it with plain arithmetic or floating-point values. The operator does not care about decimal fractions, and it does not preserve sign the way many people expect from subtraction. It works on bits, period.
Another common gotcha is that bitwise operators often coerce values to 32-bit integers in JavaScript. That means large numbers can wrap, and some bits may disappear before you ever see the result. If you are dealing with IDs, hashes, or large counters, that coercion matters.
When debugging, ask three questions: what is the input type, what width is being used, and is the value signed or unsigned? Those three details usually explain the weirdness. The operator itself is simple; the context around it is where the bugs live.
Frequently Asked Questions
What does bitwise NOT do in plain English?
It flips every bit in the number’s binary form. A 0 becomes 1 and a 1 becomes 0. The resulting bit pattern is then interpreted again as a number, usually a signed integer.
Why is ~5 equal to -6?
Because most systems use two’s complement for signed integers. In that format, ~x is equivalent to -(x + 1). So flipping 5 gives the numeric result -6.
Does bitwise NOT work on decimals?
Not directly. In languages like JavaScript, the value is first converted to an integer before the bit flip happens, so 12.9 behaves like 12. If you need decimal math, bitwise operators are the wrong tool.
Is bitwise NOT the same as logical NOT?
No. Logical NOT is usually ! and it works on truthy or falsy values. Bitwise NOT is ~ and works on the binary representation of integers, which is a much lower-level operation.
Wrapping Up
The short version: bitwise NOT flips every bit, then the language reads that new bit pattern as a number. In two’s complement, that is why ~x often looks like -(x + 1) instead of a simple negative sign.
If you are debugging masks, permissions, or weird integer coercion in JavaScript, it helps to look at the bits directly instead of guessing from the decimal result. Give the NOT calculator a spin and compare the binary and decimal outputs side by side. That usually clears the fog fast.