Bitwise calculator with shifts
Pick an operator and one or two integers, then see the operation bit by bit in a fixed width, with JavaScript's 32-bit Number rules, or with unbounded BigInt. Results are shown in binary, hex, signed and unsigned, with the exact JavaScript expression. Nothing you type leaves your browser.
How to use
- Type A as a decimal number, or with a
0x(hex),0b(binary) or0o(octal) prefix. Negative numbers use a leading minus. Underscores are ignored. - Choose the Operator: AND, OR, XOR, NOT (one input), left shift, arithmetic right shift (
>>) or logical right shift (>>>). For all but NOT and the shifts, type B as well; for a shift, B is the number of places. - Choose the Number type. 8, 16, 32 and 64-bit integer models a fixed-width type: inputs are wrapped to that width (and the tool says so), and the result is shown both signed and unsigned. JavaScript Number applies ECMAScript's rules: convert to a signed 32-bit integer, operate, and for shifts use the count modulo 32. JavaScript BigInt has no width: values are exact and negative numbers behave as an infinite string of sign bits.
- Read the bit grid. For AND, OR and XOR the grid shows A, B and the result in aligned columns (and, for widths up to 16 bits, a column-by-column table); for NOT the bits that flipped are marked. For a shift it shows the bits that left, the bits that entered, and whether they are zeros or copies of the sign bit. The truth table and the
>>versus>>>comparison appear below it. - The line labelled with the JavaScript expression shows exactly what that expression gives in a console. In a fixed-width mode it shows the wrapped values.
The four basic operations on single bits:
| A | B | A AND B | A OR B | A XOR B |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
NOT flips every bit: 0 becomes 1 and 1 becomes 0. The table is generated by code, and the tests compare each row with JavaScript's own operators.
Worked examples
Every result below is recomputed by an automated test from the tool's engine. The bit patterns were also worked out by hand first, and the results are compared with JavaScript's own operators, BigInt, and BigInt.asIntN / asUintN on thousands of random values.
AND, OR and XOR on 0xCA and 0xAC
0xCA = 11001010 and 0xAC = 10101100 (as 8-bit signed numbers, -54 and -84). Column by column:
11001010 (0xCA) 10101100 (0xAC) -------- 10001000 AND = 0x88 = 136 unsigned 11101110 OR = 0xEE = 238 unsigned 01100110 XOR = 0x66 = 102
8-bit integer
Input: 0xCA & 0xAC
Output: 8-bit: -54 & -84 = -120 signed / 136 unsigned; bits 10001000
8-bit integer
Input: 0xCA | 0xAC
Output: 8-bit: -54 | -84 = -18 signed / 238 unsigned; bits 11101110
8-bit integer
Input: 0xCA ^ 0xAC
Output: 8-bit: -54 ^ -84 = 102 signed / 102 unsigned; bits 01100110
Arithmetic versus logical right shift
-8 in 8 bits is 11111000. Arithmetic shift right by 1 copies the sign bit into the new left bit: 11111100 = -4, which is -8 divided by 2. Logical shift right puts a 0 there: 01111100 = 124.
8-bit integer
Input: -8 >> 1
Output: 8-bit: -8 >> 1 = -4 signed / 252 unsigned; bits 11111100
8-bit integer
Input: -8 >>> 1
Output: 8-bit: -8 >>> 1 = 124 signed / 124 unsigned; bits 01111100
JavaScript works on 32 bits, so the same expression gives a much bigger number. -8 is 32 bits of 1 followed by 000; shifting in a 0 at the left gives 0111...1100 = 231 - 4.
JavaScript Number
Input: -8 >>> 1
Output: -8 >>> 1 = 2147483644; bits 01111111111111111111111111111100
NOT in JavaScript
~x equals -x - 1 in two's complement, so ~5 is -6. All 32 bits flip.
JavaScript Number
Input: ~5
Output: ~5 = -6; bits 11111111111111111111111111111010
What goes wrong
These are the surprises people actually report. Each result is the tool's exact output and is covered by a test.
1 << 32 is 1 in JavaScript
The count is reduced modulo 32, so shifting by 32 is shifting by 0. The tool notes this when you type a count of 32 or more in JavaScript mode.
JavaScript Number
Input: 1 << 32
Output: 1 << 32 = 1; bits 00000000000000000000000000000001
0xFFFFFFFF | 0 is -1
0xFFFFFFFF is 4294967295 as a Number, but every JavaScript bitwise operator first converts its operands to a signed 32-bit integer. All 32 bits being 1 is -1 in that reading.
JavaScript Number
Input: 0xFFFFFFFF | 0
Output: 4294967295 | 0 = -1; bits 11111111111111111111111111111111
0x80000000 & 0xFFFFFFFF is negative
Only bit 31 survives, and in a signed 32-bit integer bit 31 is the sign. To get 2147483648 back, use >>> 0 on the result.
JavaScript Number
Input: 0x80000000 & 0xFFFFFFFF
Output: 2147483648 & 4294967295 = -2147483648; bits 10000000000000000000000000000000
Left shift past bit 31 wraps
0xFFFFFFFF is -1 after conversion, and -1 << 1 is -2. A bit that moves past bit 31 is lost, not carried into a bigger number, so left shifts cannot be used to multiply past 231 in a Number. Another consequence: (2**32 + 5) | 0 is 5, and 2**53 | 0 is 0, because the high bits are dropped on conversion.
JavaScript Number
Input: 0xFFFFFFFF << 1
Output: 4294967295 << 1 = -2; bits 11111111111111111111111111111110
>>> on a BigInt throws
Browsers' JavaScript engines refuse it; the tool reports the same message. Use >>, or cut to a width first with BigInt.asUintN. Mixing a BigInt with a Number is also an error: 1n << 2 throws a TypeError ("Cannot mix BigInt and other types, use explicit conversions", observed in Node 20.19.2 and consistent with MDN's statement that BigInt and Number cannot be mixed in arithmetic).
JavaScript BigInt
Input: 9n >>> 2n
Error: TypeError: BigInts have no unsigned right shift, use >> instead. (MDN, ECMAScript BigInt::unsignedRightShift: "Throw a TypeError exception.") A BigInt has infinitely many leading sign bits, so there is no left-most bit to fill with zeros.
A fraction is not an integer
Bitwise operators work on integers. In JavaScript 1.5 | 0 silently becomes 1; the tool rejects the fraction rather than truncate without telling you.
any
Input: 1.5
Error: "." is not a valid decimal digit. Bitwise operators work on integers.
1 << 8 in 8 bits
In a fixed-width mode the tool shows the mathematical result, 0, and warns that in C a shift by a count not smaller than the width is undefined behaviour (cppreference), so a compiler may give any result.
8-bit integer
Input: 1 << 8
Output: 8-bit: 1 << 8 = 0 signed / 0 unsigned; bits 00000000
Arithmetic right shift rounds down, not toward zero
-9 >> 1 is -5, because shifting is floor division by 2 (-4.5 rounds down to -5). Integer division in C and Java, and Math.trunc(-9 / 2), give -4. In C the result of right-shifting a negative value is implementation-defined (cppreference), although most implementations use an arithmetic shift.
Limits & gotchas
- Fixed widths are 8, 16, 32 and 64 bits. Other widths (12, 24, 128) are not offered; use BigInt mode and mask by hand.
- Inputs are wrapped, not rejected, in fixed widths. A value that does not fit the width is reduced modulo 2width and a note says so, as a C cast would do for unsigned types.
- JavaScript Number mode is 32-bit. A Number beyond 32 bits is truncated by ToInt32, exactly as in a browser console. For larger values use the 64-bit mode or BigInt.
- Shift counts. At most 1000. A BigInt shift is exact, and the bit grid widens to show the whole result, so a shift by 1000 draws a grid of about a thousand cells; scroll sideways to read it.
- Language differences. The fixed-width modes describe hardware-style two's complement results. C, C++ and Java specify some of these cases differently (undefined behaviour for oversized shifts, implementation-defined right shifts of negatives in C). The tool tells you where this matters but cannot know your compiler.
- Integers only. No floating-point operands. For the bits of a float, use the IEEE 754 page.
- Browser. Tested in a current Chrome only.
FAQ
What is the difference between >> and >>>?
>> is the arithmetic (sign-propagating) right shift: the new bits on the left copy the sign bit, so a negative number stays negative (-8 >> 1 is -4). >>> is the logical (zero-fill) right shift: the new bits are 0, so the result is never negative (MDN). In 8 bits -8 is 11111000, so >> 1 gives 11111100 = -4 and >>> 1 gives 01111100 = 124. In JavaScript, which works on 32 bits, -8 >>> 1 is 2147483644. Use >> to divide a signed number by two (rounding down) and >>> only for bit patterns.
Why is 1 << 32 equal to 1 in JavaScript?
The shift count is taken modulo 32 for Numbers. ECMAScript converts the left operand with ToInt32 and uses only the low five bits of the count, so 1 << 32 is 1 << 0 = 1, 1 << 33 is 2, and 1 << 31 is -2147483648 because bit 31 is the sign bit. Many languages differ: in C a shift by the width of the type or more is undefined behaviour (cppreference). BigInt does not have this limit: 1n << 64n is 18446744073709551616n.
Why does a bitwise operation give a negative number?
JavaScript's bitwise operators first convert their operands to signed 32-bit integers and return a signed result. 0xFFFFFFFF | 0 is -1, not 4294967295, and 0x80000000 & 0xFFFFFFFF is -2147483648. To read the result as unsigned, apply >>> 0: (0xFFFFFFFF | 0) >>> 0 is 4294967295. The tool's JavaScript Number mode shows the exact JavaScript expression and its value, and the 32-bit and 64-bit fixed-width modes show both the signed and unsigned reading.
Why does >>> throw an error on a BigInt?
A BigInt behaves as an infinitely long two's complement bit string, so there is no left-most bit to fill with zeros. The ECMAScript BigInt::unsignedRightShift operation therefore throws a TypeError, with the message MDN documents, "BigInts have no unsigned right shift, use >> instead". To get a logical shift on a BigInt, first cut it to a width with BigInt.asUintN(width, x) and then use >>. The tool shows this error for BigInt mode and explains it.
How do I clear, set or test a single bit?
Clear bit n with x & ~(1 << n), set it with x | (1 << n), toggle it with x ^ (1 << n), and test it with (x >> n) & 1. For example 0xFF & ~0x0F is 0xF0, which clears the low four bits. Two more patterns: x & (x - 1) clears the lowest set bit (12 becomes 8), and x & -x isolates it (12 gives 4). Remember the JavaScript limit: these only work on the low 32 bits of a Number; use BigInt above that.
Sources
- Ecma International / TC39: ECMAScript Language Specification: Number type, bitwise shift operators and BigInt operations Used for: Number is IEEE 754 binary64; Number shifts convert with ToInt32 or ToUint32 and take the count modulo 32; BigInt left and right shift act on an infinite two's complement string; BigInt::unsignedRightShift throws a TypeError; strings are sequences of 16-bit code units.
- MDN Web Docs: Right shift (>>) Used for: Number >> returns a 32-bit integer and copies the sign bit; BigInt >> has no truncation.
- MDN Web Docs: Unsigned right shift (>>>) Used for: >>> fills with zeros and always gives a non-negative result; it throws a TypeError for BigInt ("BigInts have no unsigned right shift, use >> instead").
- MDN Web Docs: BigInt Used for: BigInt holds integers of arbitrary size; mixing BigInt and Number in arithmetic throws a TypeError.
- 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.
- 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.
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 statement that a shift count is taken modulo 32 for Numbers is from the ECMAScript algorithms (Number::leftShift and signedRightShift use ToInt32 on the left operand and the low five bits of the count); the error message for BigInt >>> is from MDN.