Bitwise Calculator — Python source
Perform AND, OR, XOR, NOT, shifts and rotates on 8/16/32/64-bit values with exact bigint math. Enter operands in binary, octal, decimal or hex and read the result in every base plus a live bit grid. Runs 100% in your browser.
This is the Python implementation — the same logic the interactive tool runs, in a shareable, citable form.
# =============================================================================
# bitwise.py — CosmoDev polyglot showcase port of the `bitwise` tool
# -----------------------------------------------------------------------------
# Language : Python 3.10+
# Source : ported from src/lib/bitwise.ts (the canonical, live TypeScript lib)
# License : display source — part of CosmoDev's polyglot tool pages
# (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/PHP ports.
# -----------------------------------------------------------------------------
# Pure, deterministic bitwise calculator. Zero deps (standard library only).
# Python's `int` is arbitrary precision, so this is a near-direct port of the
# reference TypeScript; results are exact across all supported widths
# (8/16/32/64-bit). Operands are interpreted as width-bit two's-complement
# values: any integer is normalized to the half-open range [0, 2^width) before
# an operation, and every result is masked back into that range — so the
# returned int is always the unsigned bit-pattern of the width-bit result.
# =============================================================================
from __future__ import annotations
from typing import Literal
# Numeric base for parsing and formatting bit patterns.
Base = Literal["bin", "oct", "dec", "hex"]
# Supported bitwise operation. `not` is unary on `a`; the binary ops take `a`
# and `b`; for the shift/rotate ops `b` is the count.
Op = Literal["and", "or", "xor", "not", "shl", "shr", "rol", "ror"]
# Operating field width, in bits.
Width = Literal[8, 16, 32, 64]
# Radix per base, consumed by the manual digit parser/formatter below.
_BASE_RADIX: dict[Base, int] = {"bin": 2, "oct": 8, "dec": 10, "hex": 16}
# Lowercase digit alphabet valid for each base — drives validation and the
# per-character digit-value lookup.
_BASE_DIGITS: dict[Base, str] = {
"bin": "01",
"oct": "01234567",
"dec": "0123456789",
"hex": "0123456789abcdef",
}
def parse(value: str, base: Base) -> int:
"""Parse a numeric string in `base` into an int.
Accepts an optional leading sign and a single optional base prefix
(0x/0b/0o, case-insensitive). Raises ValueError on empty input or any digit
invalid for the requested base. The raw signed value is returned (no width
normalization); callers fold it into a field via normalize()/bitwise().
"""
trimmed = value.strip()
if trimmed in ("", "-"):
raise ValueError(f"Empty {base} value")
# Peel off an optional leading '-' so negative literals parse correctly.
sign = 1
body = trimmed
if body[0] == "-":
sign = -1
body = body[1:]
# Strip each base prefix in turn (0x, then 0b, then 0o), case-insensitive —
# mirrors the reference's chained leading-prefix removal.
for prefix in ("0x", "0b", "0o"):
if body[: len(prefix)].lower() == prefix:
body = body[len(prefix) :]
if body == "":
raise ValueError(f"Empty {base} value")
# Horner's method over the digit alphabet: one pass, exact for any length.
alphabet = _BASE_DIGITS[base]
radix = _BASE_RADIX[base]
acc = 0
for ch in body.lower():
digit = alphabet.find(ch)
if digit < 0:
raise ValueError(f"Invalid digit {ch!r} for base {base}")
acc = acc * radix + digit
return sign * acc
def _mask(width: Width) -> int:
"""Bitmask for a `width`-bit field: 2**width - 1. (Internal helper.)"""
return (1 << width) - 1
def normalize(n: int, width: Width) -> int:
"""Fold `n` into its unsigned `width`-bit two's-complement value.
The double-modulo `((n % m) + m) % m` maps negative dividends into the
canonical unsigned range [0, 2**width) — e.g. -1 at width 8 yields 255.
(Python's `%` is already floored, but the double form is kept for parity
with the reference algorithm and the other language ports.)
"""
m = 1 << width
return ((n % m) + m) % m
def format(n: int, base: Base, min_digits: int) -> str:
"""Render `n` in `base`, zero-padded to at least `min_digits` places.
Negative values carry a leading '-' and format their magnitude. `min_digits`
corresponds to the `width` parameter in the TypeScript reference (a width-bit
binary value needs exactly `width` digits).
Note: shadows the builtin ``format`` within this module, matching the TS
lib's exported ``format`` for API parity across the polyglot ports.
"""
if n < 0:
return "-" + format(-n, base, min_digits)
radix = _BASE_RADIX[base]
digits = "0" if n == 0 else _to_base(n, radix)
return digits.zfill(min_digits)
def _to_base(n: int, radix: int) -> str:
"""Convert a non-negative int to a lowercase string in `radix` (2..16)."""
alphabet = "0123456789abcdef"
out = []
while n > 0:
out.append(alphabet[n % radix])
n //= radix
return "".join(reversed(out))
def bitwise(op: Op, a: int, b: int, width: Width) -> int:
"""Apply a `width`-bit bitwise operation.
Both operands are normalized to `width` bits first, and the result is masked
back into range — so the returned int is always the unsigned bit-pattern of
the `width`-bit result.
"""
m = _mask(width)
x = normalize(a, width)
y = normalize(b, width)
if op == "and":
return x & y
if op == "or":
return x | y
if op == "xor":
return x ^ y
if op == "not":
return (~x) & m
if op == "shl":
# Left shift grows; for shift >= width the masked result is 0.
# Short-circuit to avoid building a (potentially huge) intermediate.
return 0 if y >= width else ((x << y) & m)
if op == "shr":
# x is normalized non-negative → logical (zero-filling) shift.
return 0 if y >= width else (x >> y)
if op in ("rol", "ror"):
shift = y % width # rotate amount wraps within width
if shift == 0:
return x
# A right-rotate by `shift` is a left-rotate by (width - shift).
s = shift if op == "rol" else width - shift
return ((x << s) | (x >> (width - s))) & m
raise ValueError(f"Unknown bitwise operation: {op!r}")
def to_bits(n: int, width: Width) -> str:
"""Fixed-width binary string of `width` bits (MSB first)."""
return format(normalize(n, width), "bin", width)
def flags(n: int, width: Width) -> list[int]:
"""Indices of set bits in the normalized `width`-bit pattern (LSB = 0)."""
bits = normalize(n, width)
out = []
i = 0
while bits > 0:
if bits & 1:
out.append(i)
bits >>= 1
i += 1
return out
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →