Two's complement calculator
Enter a decimal number to see its two's complement bits, or enter a hex or binary pattern to see what number it is signed and unsigned. The page shows the invert-and-add-one steps, a clickable bit grid, overflow and sign extension. Your input never leaves your browser.
How to use
- Choose the Width: 8, 16, 32 or 64 bits. Two's complement is always relative to a width; the same bits mean different numbers at different widths.
- Choose how the input is written. Decimal accepts a signed number such as
-5. Hex pattern and Binary pattern take the bits as typed: a shorter pattern is padded with zeros on the left (zero extension, never sign extension). - Read the summary: the bits, the hex form, the unsigned value and the signed value of the same bits, and whether the input fits as signed, as unsigned, as both, or as neither (overflow).
- The bit grid shows each bit with its weight. The top bit has a negative weight,
-2^(width-1); that is the whole idea of two's complement. Click a bit to flip it and watch the values change. - Below the grid, Negating this pattern shows invert, add 1 and any carry; Changing width shows sign extension, zero extension and truncation at every width; and the add check shows signed overflow and unsigned carry for adding 1.
Ranges the tool uses:
| Bits | Signed minimum | Signed maximum | Unsigned maximum |
|---|---|---|---|
| 8 | -128 | 127 | 255 |
| 16 | -32768 | 32767 | 65535 |
| 32 | -2147483648 | 2147483647 | 4294967295 |
| 64 | -9223372036854775808 | 9223372036854775807 | 18446744073709551615 |
The minimum is -2n-1, the maximum is 2n-1 - 1, and the unsigned maximum is 2n - 1. The table is generated from the same code the tool uses, and the tests check each row.
Worked examples
Each value below is recomputed by an automated test from the tool's engine; the binary arithmetic is also written out and checked separately.
A negative number: -5 in 8 bits
The top bit has weight -128. 11111011 = -128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = -128 + 123 = -5. As unsigned, the same bits are 128 + 123 = 251 = 256 - 5.
Width 8, input is decimal
Input: -5
Output: 11111011 (hex FB); unsigned 251; signed -5; status signed-only
The textbook route is "invert and add one":
Width 8
Input: -5
Output: 00000101 -> invert 11111010 -> add 1 11111011
The same bits, read from a pattern
All ones, FF, is 255 unsigned and -1 signed: -128 + 127 = -1.
Width 8, input is hex pattern
Input: FF
Output: 11111111 (hex FF); unsigned 255; signed -1
At 32 bits the pattern 80000000 is a 1 followed by 31 zeros: the most negative 32-bit integer.
Width 32, input is hex pattern
Input: 80000000
Output: 10000000000000000000000000000000 (hex 80000000); unsigned 2147483648; signed -2147483648
The one number that negates to itself
Invert 10000000 and you get 01111111; add 1 and the carry runs all the way up and gives 10000000 again. There is no +128 in 8 bits.
Width 8
Input: 10000000
Output: 10000000 -> invert 01111111 -> add 1 10000000 (same pattern)
Widening and narrowing
Widening 11111011 (-5) to 16 bits: sign extension copies the top bit, zero extension adds zeros.
Width 8, input is binary pattern
Input: 11111011
Output: sign-extended 1111111111111011; zero-extended 0000000011111011
Narrowing keeps the low bits. 300 in 16 bits is 0000000100101100; cut to 8 bits it is 00101100, which is 44 (the top 1 is lost):
Width 16, pattern 012C
Input: 0000000100101100 (300 in 16 bits)
Output: sign-extended 00101100; zero-extended 00101100
Addition: signed overflow versus carry
127 + 1 in 8 bits: 01111111 + 00000001 = 10000000. No carry leaves the top bit, but the sign flipped from positive to negative, so signed overflow happened (the mathematically correct 128 does not fit).
Add patterns, width 8
Input: 127 and 1
Output: pattern 10000000; signed -128; unsigned 128; signed overflow yes; unsigned carry no
255 + 1 in 8 bits: 11111111 + 00000001 = 1 00000000. A carry leaves the top bit, so the unsigned result does not fit; but read as signed this is -1 + 1 = 0, which is correct, so there is no signed overflow.
Add patterns, width 8
Input: 255 and 1
Output: pattern 00000000; signed 0; unsigned 0; signed overflow no; unsigned carry yes
What goes wrong
Inputs that go wrong in real programs, with the tool's exact output.
300 does not fit in 8 bits
300 needs nine bits (100101100). Most code silently keeps the low eight. The tool flags it and shows exactly which bit was dropped.
Width 8, input is decimal
Input: 300
Output: 00101100 (hex 2C); unsigned 44; signed 44; dropped bit 1, status overflow
-129 does not fit in 8 bits
-129 is below -128, the smallest 8-bit value. Its 9-bit two's complement form is 101111111; keeping 8 bits turns it into +127, a change of sign.
Width 8, input is decimal
Input: -129
Output: 01111111 (hex 7F); unsigned 127; signed 127; dropped bit 1, status overflow
128 fits as unsigned but not as signed
128 is a valid uint8 but is not a valid int8. The same bits read as signed are -128.
Width 8, input is decimal
Input: 128
Output: 10000000 (hex 80); unsigned 128; signed -128; status unsigned-only
A short binary pattern is zero-extended, not sign-extended
Typing 4 bits into an 8-bit field does not mean "negative if it starts with 1". The pattern 1010 is padded with zeros to 00001010, which is 10. If you meant the 4-bit value -6, the sign has to be extended to 11111010 first, which is what the sign-extension table does.
Width 8, input is binary pattern
Input: 1010
Output: 00001010 (hex 0A); unsigned 10; signed 10
A digit that is not a bit
Width 8, input is binary pattern
Input: 9
Error: Character "9" at position 1 is not a valid binary digit.
Why a hex number in JavaScript is not negative
0xFF is the Number 255 in JavaScript, not -1, because Numbers are not fixed-width integers. To get the 8-bit signed value, wrap it explicitly: BigInt.asIntN(8, 255n) is -1n (MDN: BigInt.asIntN). For 32 bits, 0xFFFFFFFF | 0 is -1.
Limits & gotchas
- Widths. 8, 16, 32 and 64 bits only. Odd widths such as 12 bits (common in sensors) are not offered; you can read a 12-bit value by sign-extending it by hand using the widening table.
- Input size. At most 400 characters. Numbers are exact arbitrary-size integers, so 64-bit values do not lose precision the way a JavaScript Number would above 253.
- Two's complement only. Sign-magnitude and ones' complement are other systems for signed integers and are not shown. Floating-point numbers use a sign bit and are covered on the IEEE 754 page.
- The language rules differ. The tool states what the hardware-style arithmetic gives. In C, signed overflow is undefined behaviour and a right shift of a negative value is implementation-defined (cppreference), so your compiler may not behave like the wrapped result shown here. The bitwise calculator has the JavaScript rules.
- Browser. Tested in a current Chrome only.
FAQ
How do I write -5 in 8-bit two's complement?
Write 5 in binary with 8 bits (00000101), invert every bit (11111010), then add 1 (11111011). That is hex FB, and 251 if you read the same bits as unsigned. Check by adding: 00000101 + 11111011 = 100000000 (256), and with only 8 bits kept the result is 00000000, so 11111011 behaves as -5. The page shows these steps for any input.
Why can 8 bits hold -128 but only +127?
There are 256 patterns. Zero uses one, 127 patterns are positive and 128 are negative, because the top bit is the sign and two's complement has a single zero. The extra pattern is 10000000 = -128. It has no positive twin: inverting it gives 01111111 and adding 1 gives 10000000 again, so negating the most negative number returns the same number. Wikipedia: Two's complement gives the 4-bit case, -8 to +7. In C, negating INT_MIN is undefined behaviour (cppreference).
What is the difference between sign extension and zero extension?
Both widen a bit pattern. Sign extension copies the top bit into all the new high bits, which keeps the signed value (11111011 = -5 becomes 1111111111111011 = -5 in 16 bits). Zero extension fills with 0s, which keeps the unsigned value (11111011 = 251 becomes 0000000011111011 = 251). Using the wrong one is a classic bug when a signed byte is widened: -5 turns into 251.
Why does 300 become 44 in 8 bits?
Because 300 is 100101100 in binary, nine bits. An 8-bit field keeps the low 8 bits, 00101100 = 44, and the top bit, 1, is dropped. Equivalently 300 - 256 = 44. The tool does not hide this: it marks the input as an overflow, shows the dropped bit, and shows what the value wraps to. In C, unsigned arithmetic wraps this way; signed overflow is undefined behaviour (cppreference).
How do I tell signed overflow from a carry?
They are two different flags for the same addition. A carry out of the top bit means the unsigned result did not fit (255 + 1 in 8 bits gives 00000000 with a carry, though as signed numbers -1 + 1 = 0 is perfectly correct). Signed overflow means the signed result did not fit (127 + 1 gives 10000000, which reads as -128, with no carry out). The page shows both worked examples, and the tool reports both flags for any pattern you add.
Sources
- Wikipedia: Two's complement Used for: The most significant bit is the sign; one zero and one extra negative number (a 4-bit range of -8 to +7); invert-and-add-one; sign extension repeats the most significant bit; the most negative number has no positive counterpart.
- MDN Web Docs: BigInt.asIntN() Used for: BigInt values are always encoded as two's complement; asIntN wraps a value to a signed width.
- cppreference.com: C arithmetic operators Used for: In C a shift count that is negative or not smaller than the promoted width of the left operand is undefined behaviour; signed right shift of a negative value is implementation-defined; unsigned arithmetic wraps modulo 2^n; signed overflow is undefined.
- MDN Web Docs: BigInt Used for: BigInt holds integers of arbitrary size; mixing BigInt and Number in arithmetic throws a TypeError.
- Wikipedia: Positional notation Used for: A number is written as digits multiplied by powers of the base, with the radix point separating the integer and fractional parts.
Every document above was opened and read on 2026-10-02. Documentation changes; if a page here disagrees with the current docs, trust the docs and tell us.
The tests check every width against BigInt.asIntN and BigInt.asUintN on random values and against hand-worked bit patterns.