I've "known" two's complement since a CS101 lecture — flip the bits, add one, done. But I didn't really internalize the range-checking part until I tried to build a small calculator that converts between decimal and N-bit binary (showing 1's and 2's complement side by side), and had to handle arbitrary bit widths instead of the fixed int8/int16/int32 everyone just memorizes.
The part everyone skips: range checking
For an N-bit signed number, the range is asymmetric: -2^(N-1) to 2^(N-1) - 1. For 8 bits that's -128 to 127, not -127 to 127. The reason: there's only one all-zero bit pattern (that's 0), so the "extra" negative slot that would otherwise be wasted on a redundant zero goes to the most negative number instead.
That asymmetry means "does this number fit in N bits" isn't a simple abs(num) <= 2^(N-1) - 1 check — the bound is different depending on sign:
function limitNum(num, numLen) {
const baseNum = 2 ** (numLen - 1);
const maxNum = baseNum - 1; // 127 for 8 bits
const minNum = 0 - baseNum; // -128 for 8 bits
return num > maxNum || num < minNum ? 0 : 1;
}
Miss this and your calculator will correctly accept -128 in 8 bits, but also let +128 slide through as if it fit — or worse, silently wrap around and hand back a nonsense value instead of telling the user it's out of range.
Flip the bits, then add one — except "add one" isn't trivial in string-land
Once a number is in binary, its two's complement is "invert every bit, then add 1." Trivial with actual integers — but I was storing binary as strings (so I could show arbitrary bit widths padded with leading zeros), which means "add 1" has to be done by hand, propagating the carry bit by bit from the right:
function notString(binary) {
return binary.split("").map(bit => (bit === "0" ? "1" : "0")).join("");
}
function addOne(binary) {
const bits = binary.split("");
for (let i = bits.length - 1; i >= 0; i--) {
if (bits[i] === "1") {
bits[i] = "0"; // carry the 1, keep going left
} else {
bits[i] = "1"; // found a 0, flip it, carry absorbed, done
return bits.join("");
}
}
return bits.join(""); // all 1s overflowed — technically wraps around
}
This is exactly what a hardware full-adder does when adding 1 to a binary number: propagate the carry until it hits a bit that stops it. Writing it out in string form makes visible something that's normally hidden inside the + operator.
Going backwards is the same trick, reversed
The calculator also needs to go the other direction — from a two's complement bit pattern back to the original magnitude, which is useful when you're staring at a hex dump and need to know what negative number it actually represents. It's the same two operations, just chained to get back to source:
function fromTwosComplement(complement) {
const inverted = complement.split("").map(bit => (bit === "0" ? "1" : "0")).join("");
return (parseInt(inverted, 2) + 1).toString(2);
}
Invert, add one, done. Two's complement is its own inverse operation, which is a big part of why nearly every CPU uses it: subtraction becomes addition of a complement, so there's no separate circuitry needed just for negative numbers.
Where I actually use this
I don't reach for a two's complement calculator often, but the few times a year I do — debugging a serialization bug, or double-checking a bitwise op in a language with unfamiliar int-width rules — it's genuinely useful to see binary, 1's complement, 2's complement, and decimal side by side instead of working it out by hand or trusting a REPL's implicit int width. I cleaned up the version I built for that into a small free tool: Two's Complement Calculator. No sign-up, works for any bit width you throw at it.
Available in other languages
- 二進制補數計算機 — 繁體中文
- 二进制补码计算器 — 简体中文
- Two's Complement Calculator — English
- 2の補数計算機 — 日本語
- 2의 보수 계산기 — 한국어
- Calculateur de complément binaire — Français
- Калькулятор двоичного дополнительного кода — Русский
- Zweierkomplement-Rechner — Deutsch
- Kalkulator Komplement Bilangan Biner — Bahasa Indonesia
- Calculadora de Complemento a Dos — Español
- Máy Tính Bù Số Nhị Phân — Tiếng Việt
- เครื่องคำนวณคอมพลีเมนต์เลขฐานสอง — ไทย
- Kalkulator uzupełnień liczb binarnych — Polski
- İkili Tamamlayıcı Hesap Makinesi — Türkçe
- Calcolatrice di Complementi Binari — Italiano
- Calculadora de Complemento de Dois — Português
- Binaire Aanvullingscalculator — Nederlands
- Калькулятор Доповнень Двійкових Чисел — Українська
Top comments (0)