Number Base Converter — C++ source
Convert numbers between binary, octal, decimal and hexadecimal. BigInt-powered, so it handles arbitrarily large values without precision loss.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// number-base — C++ port: arbitrary-precision base conversion (bases 2-36).
#include <algorithm>
#include <cctype>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
inline constexpr char kDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
// Arbitrary-precision integer: little-endian base-2^32 limbs; empty == zero.
struct Big {
bool neg = false;
std::vector<uint32_t> mag;
// this = this * mul + add — one Horner step over the limbs.
void mul_add(uint32_t mul, uint32_t add) {
uint64_t carry = add;
for (size_t i = 0; i < mag.size(); i++) {
uint64_t t = (uint64_t)mag[i] * mul + carry;
mag[i] = (uint32_t)t;
carry = t >> 32;
}
while (carry) mag.push_back((uint32_t)carry), carry >>= 32;
}
// this /= d; returns this % d (used to peel least-significant digits).
uint32_t divmod(uint32_t d) {
uint64_t rem = 0;
for (size_t i = mag.size(); i-- > 0;) {
uint64_t cur = rem << 32 | mag[i];
mag[i] = (uint32_t)(cur / d);
rem = cur % d;
}
while (!mag.empty() && mag.back() == 0) mag.pop_back();
return (uint32_t)rem;
}
};
// Map a lowercase character to its value; -1 when not a digit.
int digit_value(char c) {
return c >= '0' && c <= '9' ? c - '0' : c >= 'a' && c <= 'z' ? c - 'a' + 10 : -1;
}
// Parse `s` as an integer in `base` (2-36); nullopt on invalid input. A radix
// prefix is stripped only when it agrees with the base.
std::optional<Big> parse_big(const std::string& s, int base) {
if (base < 2 || base > 36) return std::nullopt;
size_t lo = s.find_first_not_of(" \t\r\n"), hi = s.find_last_not_of(" \t\r\n");
if (lo == std::string::npos) return std::nullopt;
std::string t = s.substr(lo, hi - lo + 1);
std::transform(t.begin(), t.end(), t.begin(), [](unsigned char c) { return (char)std::tolower(c); });
Big b;
if (t[0] == '-' || t[0] == '+') b.neg = t[0] == '-', t = t.substr(1);
if (t.size() >= 2 && t[0] == '0') {
char p = t[1];
if ((p == 'x' && base == 16) || (p == 'b' && base == 2) || (p == 'o' && base == 8))
t = t.substr(2);
}
if (t.empty()) return std::nullopt;
for (char c : t) {
int d = digit_value(c);
if (d < 0 || d >= base) return std::nullopt;
b.mul_add(base, d);
}
if (b.mag.empty()) b.neg = false; // normalize -0
return b;
}
// Render `v` in `base`; "" for an unsupported base, matching the TS lib.
std::string format_big(const Big& v, int base) {
if (base < 2 || base > 36) return "";
Big t = v;
if (t.mag.empty()) return "0";
bool neg = t.neg;
std::string out;
while (!t.mag.empty()) out += kDigits[t.divmod(base)];
if (neg) out += '-';
std::reverse(out.begin(), out.end()); // digits were peeled LSD first
return out;
}
// value(from_base) -> to_base; nullopt when it does not parse.
std::optional<std::string> convert_base(const std::string& value, int from, int to) {
auto n = parse_big(value, from);
if (!n) return std::nullopt;
return format_big(*n, to);
}
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 →