Programmer Calculator

Convert between binary, decimal, hex and octal and perform bitwise operations, with two's complement handling and the shift behaviour that catches people out.

Decimal
Hex
Octal
Binary

Result:

In hexadecimal, 0b is not a prefix — it is two digits

Input used to be cleaned by stripping a leading 0x, 0b or 0o before parsing, without checking which base was selected. That is fine in binary. In hex it removes two perfectly good digits.

Typed, in hexRead asCorrect value
0be 14 190
0b1 1 177
0bad 173 2989
0beef 3823 48879
0b 0 11
abc 2748 2748 (unchanged)
0xFF 255 255 (unchanged)

5 of the 7 were wrong, and the worst of them — 0beef — came out as 3823 instead of 48879. Nothing complained, and the answer was plausible enough to write down. The prefix is now removed only when it belongs to the base being read, so 0x still works in hex, 0b in binary, and 0o in octal.

The browser's own bitwise operators are 32 bits wide, and signed

Which is a strange foundation for a 64-bit calculator, so this page does not use them. Write a & b in JavaScript and both operands are first converted to 32-bit signed integers: everything above bit 31 is discarded, and bit 31 itself is read as a minus sign.

ExpressionNative operatorsThis page
1 << 31 -2147483648 2147483648
1 << 30 1073741824 1073741824 (same)
1 << 32 1 4294967296
0xFFFFFFFF | 0 -1 4294967295
0xFFFF | 0 65535 65535 (same)
2 ** 32 | 0 0 4294967296
~0 -1 18446744073709551615
~0xFF -256 18446744073709551360

6 of the 8 come out differently, and the 2 that agree are the ones below 2³¹. None of it throws. A calculator built the obvious way would agree with a correct one on every small value and disagree, silently, above that — which is exactly the range you open a programmer's calculator to check.

The shift count wraps too: 1 << 32 is 1, not 4294967296, because the count is taken modulo 32. And 0xFFFFFFFF | 0 is −1 while 0xFFFFFFFF >>> 0 is 4294967295 — the same bits, read once as signed and once as unsigned.

So the width here is a decision rather than a leftover

Values are held as arbitrary-precision integers and masked to 64 bits after every operation. That has two consequences worth seeing.

255 shifted left byResultBits before masking
8 65280 16
63 9223372036854775808 71
64 0 72
100 0 108
1000 0 1008

A shift of 64 or more gives zero, as it should. Without the mask the intermediate would keep growing — a shift of 1000 builds a number over a thousand bits wide on its way to an answer of nothing. And NOT of zero fills the width: 18446744073709551615, rather than the −1 the native operator gives.

How to use

  1. Enter a value in any base.
  2. Read it in every other base at once.
  3. Apply bitwise operations between two values.
  4. Set the word size before working with negatives.

Frequently asked questions

What is two's complement?

The standard way of representing negative integers, where a negative is formed by inverting every bit and adding one. Its advantage is that addition and subtraction work identically for signed and unsigned values, so the hardware needs only one adder rather than separate circuits.

Why is the negative range one larger than the positive?

Because zero occupies a slot in the positive half. An 8-bit signed value runs from minus 128 to plus 127, not minus 127 to 127. The consequence is that negating the most negative value overflows and returns itself, which is a genuine and occasionally serious bug.

What is the difference between logical and arithmetic right shift?

What fills the vacated bits. A logical shift brings in zeros; an arithmetic shift copies the sign bit, preserving negativity. Using the wrong one on a negative number turns it into a large positive, and different languages default differently.

Is shifting the same as multiplying or dividing by a power of two?

For unsigned values and left shifts within range, yes. For negatives it diverges: arithmetic right shift rounds toward negative infinity while integer division rounds toward zero, so shifting minus 7 right by one gives minus 4 while dividing gives minus 3.

What is XOR useful for?

Toggling bits and detecting difference. Applying the same XOR twice returns the original value, which underpins simple checksums, parity bits and the one-time pad. It is also how you swap two variables without a temporary, which is a clever trick and usually worse than the obvious version.

Why does bitwise AND with a mask isolate bits?

Because AND yields 1 only where both inputs are 1, so a mask of 1s selects those positions and 0s discard the rest. Masking is the standard way to read packed flags, extract a colour channel, or take a value modulo a power of two.

🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.