Base Conversion in Programming Languages: A Practical Guide
Why Base Conversion Matters in Programming
Every programming language stores numbers internally in binary, but developers work with decimal, hexadecimal, octal, and binary representations depending on the task. Color codes use hex. File permissions use octal. Bit masks use binary. Configuration values might arrive as hex strings from an API.
Knowing how to convert between bases in your language of choice — and understanding what happens under the hood — prevents subtle bugs like integer overflow, string formatting errors, and silent truncation.
Built-in Conversion Functions
Most languages provide built-in support for common base conversions. Here's a quick reference:
| Language | Decimal → Hex | Decimal → Binary | Hex → Decimal |
|---|---|---|---|
| Python | hex(n) | bin(n) | int(s, 16) |
| JavaScript | n.toString(16) | n.toString(2) | parseInt(s, 16) |
| Java | Integer.toHexString(n) | Integer.toBinaryString(n) | Integer.parseInt(s, 16) |
| Go | fmt.Sprintf("%x", n) | fmt.Sprintf("%b", n) | strconv.ParseInt(s, 16, 0) |
| Rust | format!("{:x}", n) | format!("{:b}", n) | u32::from_str_radix(s, 16) |
Python
Python makes base conversion straightforward with int() and toString() variants:
# Parse any base to decimal
int('FF', 16) # 255
int('377', 8) # 255
int('11111111', 2) # 255
# Decimal to other bases (returns string with prefix)
hex(255) # '0xff'
oct(255) # '0o377'
bin(255) # '0b11111111'
# Format without prefix
format(255, 'x') # 'ff'
format(255, 'b') # '11111111'
For bases beyond 16, you need a custom function — Python doesn't include one.
JavaScript
JavaScript uses toString(radix) for output and parseInt(string, radix) for input:
// Decimal to other bases
(255).toString(16) // 'ff'
(255).toString(8) // '377'
(255).toString(2) // '11111111'
// Other bases to decimal
parseInt('ff', 16) // 255
parseInt('377', 8) // 255
parseInt('11111111', 2) // 255
Caveat: parseInt('08') returns 0 in older JavaScript engines because it interpreted the leading 0 as octal. Always pass the radix explicitly.
Java
Java provides Integer and Long class methods:
// Decimal to other bases
Integer.toHexString(255) // "ff"
Integer.toOctalString(255) // "377"
Integer.toBinaryString(255) // "11111111"
// Other bases to decimal
Integer.parseInt("ff", 16) // 255
Integer.parseInt("377", 8) // 255
Integer.parseInt("11111111", 2) // 255
For arbitrary bases (2–36), use Integer.toString(n, radix) and Integer.parseInt(s, radix).
Writing a Manual Base Converter
Understanding the algorithm helps you handle cases built-in functions don't cover — like bases above 36 or custom digit sets.
Decimal to Any Base
Divide by the target base repeatedly and collect remainders:
def to_base(n, base):
if n == 0:
return '0'
digits = '0123456789abcdefghijklmnopqrstuvwxyz'
result = ''
while n > 0:
result = digits[n % base] + result
n //= base
return result
to_base(255, 16) # 'ff'
to_base(255, 2) # '11111111'
to_base(255, 36) # '73'
Any Base to Decimal
Multiply each digit by its place value and sum:
def from_base(s, base):
digits = '0123456789abcdefghijklmnopqrstuvwxyz'
result = 0
for char in s.lower():
result = result * base + digits.index(char)
return result
from_base('ff', 16) # 255
from_base('11111111', 2) # 255
Common Pitfalls
Case Sensitivity
Hex strings may arrive uppercase (FF) or lowercase (ff). Always normalize case before parsing, or use case-insensitive comparison.
Zero Prefix Ambiguity
A leading 0 can mean octal or just be a zero-padded decimal. In Python 3, 0123 is a syntax error. In older JavaScript, it parsed as octal. Always use explicit radix parameters.
Negative Numbers
toString(radix) in JavaScript produces a signed representation for negative numbers: (-255).toString(16) returns '-ff'. If you're working with two's complement representations, you need manual bit masking.
Floating-Point Precision
Built-in functions work with integers. Converting large floating-point numbers between bases introduces precision loss. Use BigInt (JavaScript) or decimal (Python) for large values.
Arbitrary Bases Beyond 36
Most built-in converters max out at base 36 (0–9, a–z). For higher bases, extend the digit set:
def to_base62(n):
"""Base62: 0-9, a-z, A-Z — common for URL shorteners."""
digits = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
if n == 0:
return '0'
result = ''
while n > 0:
result = digits[n % 62] + result
n //= 62
return result
Base62 is popular for URL shortening and unique ID generation because it produces compact, URL-safe strings.
Key Takeaways
- Most languages have built-in functions for common bases (2, 8, 10, 16) — learn them before writing custom code
- Always pass the radix explicitly to
parseInt()and similar functions to avoid ambiguity - Manual conversion algorithms (divide-and-collect, multiply-and-sum) work for any base up to your digit set size
- Watch out for case sensitivity, zero-prefix ambiguity, negative number handling, and floating-point precision
- For bases above 36, extend the digit set with uppercase letters or custom characters
- Understand the algorithm even if you use built-in functions — it helps debug edge cases
Related Guides
Try It Yourself
Convert between any number base instantly with our free Number Base Converter. Enter a value in decimal, binary, octal, or hex and see all conversions at once.