Skip to content

Number Base Converter — JavaScript source

Convert numbers between binary, octal, decimal and hexadecimal. BigInt-powered, so it handles arbitrarily large values without precision loss.

This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

// number-base - Arbitrary-precision base conversion (BigInt).
// Language: JavaScript (ES2020+, uses native BigInt).
//
// CosmoDev polyglot showcase port of the `number-base` tool, ported from
// src/lib/numberBase.ts. Display source - part of CosmoDev's polyglot tool pages.
//
// The conversion runs entirely on JavaScript's native arbitrary-precision
// BigInt, so results are exact for inputs of any length. Bases 2-36 are
// supported, matching the canonical TypeScript implementation. No crypto or
// external dependencies are involved - this is pure string/number logic.

const DIGITS = '0123456789abcdefghijklmnopqrstuvwxyz';

// Map a single character to its numeric value: 0-9 for '0'-'9', 10-35 for
// 'a'-'z'. Returns -1 when the character is not a valid digit in any base.
function digitValue(ch) {
  if (ch >= '0' && ch <= '9') return ch.charCodeAt(0) - 48;
  if (ch >= 'a' && ch <= 'z') return ch.charCodeAt(0) - 87;
  return -1;
}

// Parse `str` as an integer written in `base` (2-36). Returns a BigInt on
// success, or null when the base is out of range or `str` holds an invalid
// digit. A leading sign (`+`/`-`) is honored, and a radix prefix (`0x`/`0b`/
// `0o`) is tolerated only when it agrees with the requested base - so "0xFF"
// is meaningful for base 16 but rejected for base 10.
export function parseBigInt(str, base) {
  if (base < 2 || base > 36) return null;
  let s = str.trim().toLowerCase();
  let neg = false;
  if (s.startsWith('-')) { neg = true; s = s.slice(1); }
  else if (s.startsWith('+')) { s = s.slice(1); }
  if ((s.startsWith('0x') && base === 16) ||
      (s.startsWith('0b') && base === 2) ||
      (s.startsWith('0o') && base === 8)) {
    s = s.slice(2);
  }
  if (!s) return null;
  // Horner's method over the digits, all in BigInt arithmetic.
  let result = 0n;
  const b = BigInt(base);
  for (const ch of s) {
    const d = digitValue(ch);
    if (d < 0 || d >= base) return null;
    result = result * b + BigInt(d);
  }
  return neg ? -result : result;
}

// Render a BigInt `value` as a lowercase string in `base` (2-36). Returns the
// empty string for an unsupported base; the sign of zero is never emitted.
export function formatBigInt(value, base) {
  if (base < 2 || base > 36) return '';
  if (value === 0n) return '0';
  let v = value;
  let neg = false;
  if (v < 0n) { neg = true; v = -v; }
  const b = BigInt(base);
  let out = '';
  // Peel off the least-significant digit each iteration and prepend it.
  while (v > 0n) {
    out = DIGITS[Number(v % b)] + out;
    v /= b;
  }
  return neg ? '-' + out : out;
}

// Convenience wrapper: parse `value` in `fromBase`, then re-emit it in
// `toBase`. Returns null when the input does not parse.
export function convertBase(value, fromBase, toBase) {
  const n = parseBigInt(value, fromBase);
  if (n === null) return null;
  return formatBigInt(n, toBase);
}

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 →