Hex Math, All Bases Covered
Arithmetic and bitwise operations on hex values with live output in hex, decimal, octal, and binary.
Code reference: bitwise and base conversion across languages
The calculator above performs hex arithmetic and bitwise operations with simultaneous output in hexadecimal, decimal, octal, and binary. The reference below covers the same operations as written in production source code, so the value you computed in the browser can be carried straight into the language you actually ship in.
Number literal syntax by language
| Language | Hex | Octal | Binary |
|---|---|---|---|
| C, C++ | 0xFF | 0377 (bare leading zero) | 0b11111111 (GCC ext, C++14+) |
| Rust | 0xFF | 0o377 | 0b11111111 |
| Go | 0xFF | 0o377 or 0377 | 0b11111111 |
| Java | 0xFF | 0377 | 0b11111111 |
| Kotlin | 0xFF | not supported | 0b11111111 |
| C# | 0xFF | not supported | 0b11111111 |
| Swift | 0xFF | 0o377 | 0b11111111 |
| Python 3 | 0xFF | 0o377 | 0b11111111 |
| Ruby | 0xFF | 0o377 or 0377 | 0b11111111 |
| PHP 8.1+ | 0xFF | 0377 or 0o377 | 0b11111111 |
| Perl | 0xFF | 0377 | 0b11111111 |
| JavaScript | 0xFF | 0o377 | 0b11111111 |
| TypeScript | 0xFF | 0o377 | 0b11111111 |
| Bash arithmetic | $((0xFF)) | $((0377)) | $((2#11111111)) |
| PowerShell | 0xFF | not direct | 0b11111111 (PS 7+) |
| PostgreSQL | x'FF'::int | n/a | b'11111111'::int |
| MySQL | 0xFF | n/a | b'11111111' |
| Lua 5.3+ | 0xFF | n/a | n/a |
Underscores as digit separators (0xFF_FF_FF_FF) are accepted in Rust, Go, Java 7+, C# 7+, Swift, Kotlin, Python 3.6+, and Ruby. C and C++ require single quotes instead (0xFF'FF'FF'FF). PHP and JavaScript use the same single-underscore form in 7.4+ and ES2021.
Bitwise operations and multi-base output
Systems languages: C, C++, Rust, Go
| Language | Apply XOR | Print as hex, decimal, octal |
|---|---|---|
| C | uint32_t c = a ^ b; | printf("0x%X %u 0%o\n", c, c, c); |
| C++ (std::format) | auto c = a ^ b; | std::format("0x{:X} {} 0o{:o}", c, c, c) |
| Rust | let c: u32 = a ^ b; | format!("0x{:X} {} 0o{:o}", c, c, c) |
| Go | c := a ^ b | fmt.Sprintf("0x%X %d 0o%o", c, c, c) |
The full operator set is identical across these four: &, |, ^, ~, <<, >>. Signedness matters for right shift. An unsigned right shift fills with zero, a signed right shift on a negative value fills with one. C, C++, and Go pick behavior based on the variable’s type. Rust requires an explicit unsigned or signed type at the binding site.
JVM and .NET: Java, Kotlin, C#, Swift
| Language | Apply XOR | Logical (zero-fill) right shift |
|---|---|---|
| Java | int c = a ^ b; | int c = a >>> n; |
| Kotlin | val c = a xor b | val c = a ushr n |
| C# | int c = a ^ b; | int c = (int)((uint)a >> n); |
| Swift | let c = a ^ b | let c = Int(UInt32(bitPattern: a) >> n) |
Java is the outlier with its dedicated >>> triple-arrow for logical right shift. Kotlin spells operators as keywords: and, or, xor, inv, shl, shr, ushr. C# and Swift route through the unsigned type to force zero-fill. C# 11 added >>> matching Java syntax.
JavaScript and TypeScript
| Operation | Number (32-bit truncated) | BigInt (arbitrary precision) |
|---|---|---|
| AND | a & b | a & b (both operands BigInt) |
| OR | a | b | a | b |
| XOR | a ^ b | a ^ b |
| NOT | ~a (returns int32) | ~a (infinite-width two’s complement) |
| Left shift | a << n | a << BigInt(n) |
| Signed right shift | a >> n | a >> BigInt(n) |
| Zero-fill right shift | a >>> n | not available on BigInt |
const a = 0xFFFFFFFFn;
const b = 0x0F0Fn;
const c = a ^ b;
console.log(c.toString(16).toUpperCase()); // "FFFFF0F0"
console.log(c.toString(10)); // "4294967280"
console.log(c.toString(8)); // "37777770360"
console.log(c.toString(2)); // "11111111111111111111000011110000"The n suffix marks BigInt literals. Mixing BigInt and Number in the same expression throws a TypeError. Convert one side first with BigInt(x) or Number(x).
Scripting: Python, Ruby, PHP, Perl
| Language | Apply XOR | Format result in four bases |
|---|---|---|
| Python | c = a ^ b | f"{c:#x} {c} {c:#o} {c:#b}" |
| Ruby | c = a ^ b | "%#x %d %#o %#b" % [c, c, c, c] |
| PHP | $c = $a ^ $b; | sprintf("%X %d %o %b", $c, $c, $c, $c) |
| Perl | $c = $a ^ $b; | sprintf("%X %d %o %b", $c, $c, $c, $c) |
Python and Ruby integers grow without bound, so NOT on a positive value returns a negative because the result is interpreted as infinitely-wide two’s complement. To recover the 32-bit unsigned view: (~x) & 0xFFFFFFFF. The same mask applies to Perl’s ~ operator on platforms where the integer width is configurable at build time.
Shells: Bash, Zsh, PowerShell
| Shell | Apply XOR | Convert hex string to decimal |
|---|---|---|
| Bash | c=$(( a ^ b )) | echo $((16#FF)) or printf "%d\n" 0xFF |
| Zsh | (( c = a ^ b )) | printf "%d\n" 0xFF |
| PowerShell | $c = $a -bxor $b | [Convert]::ToInt32("FF", 16) |
Bash arithmetic context ($(( ))) covers &, |, ^, ~, <<, >>. PowerShell spells the same operators out as -band, -bor, -bxor, -bnot, -shl, -shr. Both default to 64-bit signed math, so a value above 0x7FFFFFFFFFFFFFFF overflows silently in Bash and wraps to a negative in PowerShell.
Databases: PostgreSQL, MySQL, SQLite
| Database | Apply XOR | Output as hex string |
|---|---|---|
| PostgreSQL | SELECT a # b; (note: # is XOR) | SELECT to_hex(c); |
| MySQL | SELECT a ^ b; | SELECT HEX(c); |
| SQLite | SELECT a ^ b; | SELECT printf('%X', c); |
PostgreSQL is the outlier. Its XOR operator is #, and ^ is exponentiation. MySQL and SQLite follow C convention. None of the three has a built-in binary-string formatter, so binary output usually requires a recursive CTE that divides the value by two and concatenates the remainder.
Common hex constants and bit patterns
| Hex | Decimal | Binary | Typical use |
|---|---|---|---|
0x01 | 1 | 00000001 | Bit 0 enable flag |
0x0F | 15 | 00001111 | Low nibble mask |
0xF0 | 240 | 11110000 | High nibble mask |
0xFF | 255 | 11111111 | Single-byte mask, u8 max |
0x80 | 128 | 10000000 | Sign bit of a byte |
0xFFFF | 65,535 | 16 ones | u16 max, 16-bit address mask |
0xFFFFFFFF | 4,294,967,295 | 32 ones | u32 max, all-bits-set |
0x7FFFFFFF | 2,147,483,647 | 0 + 31 ones | i32 max (INT_MAX) |
0x80000000 | 2,147,483,648 | 1 + 31 zeros | i32 sign bit (INT_MIN as unsigned view) |
0xCAFEBABE | 3,405,691,582 | mixed | Java .class file magic number |
0xDEADBEEF | 3,735,928,559 | mixed | Common uninitialized-memory poison |
0xFEEDFACE | 4,277,009,102 | mixed | Mach-O magic number |
0xBAADF00D | 3,131,961,357 | mixed | LocalAlloc uninitialized marker on Windows |
The poison patterns (0xDEADBEEF, 0xBAADF00D, 0xFEEDFACE) appear in uninitialized memory or unmapped regions on many platforms. They are chosen to be visibly wrong in a debugger and pronounceable when read aloud during a pairing session.
Width and signedness: NOT and shift across languages
| Language | NOT width | Right shift on a negative value |
|---|---|---|
| C, C++ | type-dependent (uint8_t → 8 bits, int → typically 32) | implementation-defined; in practice arithmetic |
| Rust | type-dependent and explicit at binding | arithmetic on signed, logical on unsigned |
| Go | type-dependent and explicit at binding | arithmetic on signed, logical on unsigned |
| Java | always 32 (int) or 64 (long) | arithmetic with >>, logical with >>> |
| C# | 32 or 64 by default | arithmetic with >>, logical via cast or >>> (C# 11+) |
| Swift | type-dependent | arithmetic on signed, logical on unsigned |
| Python | infinite (NOT returns a negative) | arithmetic |
| Ruby | infinite (same as Python) | arithmetic |
| JavaScript Number | 32 bits (operand is truncated to int32 first) | arithmetic with >>, logical with >>> |
| JavaScript BigInt | infinite | arithmetic only (no >>>) |
| Bash, Zsh | 64-bit signed | arithmetic |
| PowerShell | 32 or 64 depending on type | arithmetic |
The pattern: anything with a fixed-width type has a sensible NOT. Anything with arbitrary-precision integers (Python, Ruby, JavaScript BigInt) treats NOT as infinitely-wide two’s complement and requires an explicit mask to recover the byte or word view that the embedded world expects.
Related concepts
- Two’s complement: how negative integers are encoded as bit patterns and why
~xequals-(x+1)for any fixed-width signed type. - Endianness: byte order for multi-byte values in memory.
0x1234may be stored as12 34(big-endian) or34 12(little-endian). - Hamming weight: the count of set bits in a value. Reachable in most languages as
popcount,bitCount, orbit_count. - Bit fields and packed structs: C and C++ syntax for naming individual bit ranges inside a single integer.
- De Bruijn sequences: a technique for finding the lowest set bit in constant time using a small lookup table.