Bitwise Calculator — TypeScript 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 TypeScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Pure, deterministic bitwise calculator. Zero deps. Operates on `bigint` so
// results are exact across all supported widths (8/16/32/64-bit). Operands are
// interpreted as width-bit two's-complement values: any bigint 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 bigint is always the unsigned
// bit-pattern of the width-bit result.
// Digit math lives in bigintBaseCore; this module defines the typed-throw
// contract (0x/0b/0o prefixes stripped unconditionally).
import { parseDigits, formatDigits } from './bigintBaseCore';
export type Base = 'bin' | 'oct' | 'dec' | 'hex';
export type Op = 'and' | 'or' | 'xor' | 'not' | 'shl' | 'shr' | 'rol' | 'ror';
export type Width = 8 | 16 | 32 | 64;
const BASE_RADIX: Record<Base, number> = { bin: 2, oct: 8, dec: 10, hex: 16 };
/** Parse a numeric string in `base` into a bigint. Strips 0x/0b/0o prefixes. */
export function parse(value: string, base: Base): bigint {
const r = parseDigits(value, BASE_RADIX[base], { strictPrefix: false });
if (r.ok) return r.value;
if (r.reason === 'empty') throw new Error(`Empty ${base} value`);
throw new Error(`Invalid digit '${r.ch}' for base ${base}`);
}
/** Mask for a `width`-bit field: 2^width - 1. */
function mask(width: Width): bigint {
return (1n << BigInt(width)) - 1n;
}
/** Normalize any bigint to its unsigned width-bit two's-complement value. */
export function normalize(n: bigint, width: Width): bigint {
const m = 1n << BigInt(width);
return ((n % m) + m) % m;
}
/** Format `n` in `base`, zero-padded to at least `width` digits. Negatives carry a leading '-'. */
export function format(n: bigint, base: Base, width: number): string {
return formatDigits(n, BASE_RADIX[base], { minDigits: width });
}
/**
* Apply a width-bit operation. `a` is the (unary) operand for `not`; `b` is the
* second operand for binary ops and the shift/rotate count for shl/shr/rol/ror.
* Both operands are normalized to width-bit two's complement first; the result
* is masked to `width` bits.
*/
export function bitwise(op: Op, a: bigint, b: bigint, width: Width): bigint {
const m = mask(width);
const x = normalize(a, width);
const y = normalize(b, width);
switch (op) {
case 'and': return x & y;
case 'or': return x | y;
case 'xor': return x ^ y;
case 'not': return (~x) & m;
case 'shl': return (x << y) & m;
case 'shr': return x >> y; // x is normalized non-negative → logical shift
case 'rol':
case 'ror': {
const w = BigInt(width);
const shift = y % w; // rotate amount wraps within width
if (shift === 0n) return x;
const s = op === 'rol' ? shift : w - shift;
return ((x << s) | (x >> (w - s))) & m;
}
}
}
/** Fixed-width binary string of `width` bits (MSB first). */
export function toBits(n: bigint, width: Width): string {
return format(normalize(n, width), 'bin', width);
}
/** Indices of set bits (LSB = index 0), normalized to `width`. */
export function flags(n: bigint, width: Width): number[] {
const bits = normalize(n, width);
const out: number[] = [];
let i = 0;
for (let v = bits; v > 0n; v >>= 1n) {
if (v & 1n) out.push(i);
i++;
}
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 →