Number base conversion is one of the most fundamental skills in computer science. Whether you're debugging low-level code, working with memory addresses, or analyzing network packets, understanding different number systems is essential. This comprehensive guide covers the theory, algorithms, and practical implementations of base conversion.

Understanding Number Systems

What is a Number Base?

A number base (or radix) defines how many unique digits are used to represent numbers. The base determines the positional value of each digit.

Base Name Digits Used Common Use
2 Binary 0, 1 Computer hardware, bit operations
8 Octal 0-7 Unix file permissions
10 Decimal 0-9 Daily life, human counting
16 Hexadecimal 0-9, A-F Memory addresses, color codes

Positional Notation

In any base system, a number's value is calculated by:

Value = Σ (digit × base^position)

For example, the decimal number 1234:

1234₁₀ = 1×10³ + 2×10² + 3×10¹ + 4×10⁰
       = 1000 + 200 + 30 + 4
       = 1234

Binary Number System (Base 2)

Why Binary Matters

Computers use binary because electronic circuits have two stable states: on (1) and off (0). Every piece of data in a computer—from text to images to programs—is ultimately represented in binary.

Binary to Decimal Conversion

To convert binary to decimal, multiply each bit by its positional power of 2:

10110₂ = 1×2⁴ + 0×2³ + 1×2² + 1×2¹ + 0×2⁰
       = 16 + 0 + 4 + 2 + 0
       = 22₁₀

Decimal to Binary Conversion

Use the repeated division method:

22 ÷ 2 = 11 remainder 0
11 ÷ 2 = 5  remainder 1
5  ÷ 2 = 2  remainder 1
2  ÷ 2 = 1  remainder 0
1  ÷ 2 = 0  remainder 1

Reading remainders bottom-up: 10110₂

Binary Arithmetic

Addition:

  1011  (11)
+ 0110  (6)
------
 10001  (17)

Rules: 0+0=0, 0+1=1, 1+0=1, 1+1=10 (carry 1)

Subtraction using Two's Complement:

To subtract A - B:
1. Find two's complement of B (invert bits, add 1)
2. Add A + two's complement of B

Hexadecimal Number System (Base 16)

Hexadecimal Digits

Decimal Hex Binary
0-9 0-9 0000-1001
10 A 1010
11 B 1011
12 C 1100
13 D 1101
14 E 1110
15 F 1111

Why Hexadecimal?

Hexadecimal is popular because:

  1. Compact representation: One hex digit = 4 binary bits
  2. Easy conversion: Direct mapping to binary
  3. Human readable: Shorter than binary, more intuitive than decimal for byte values

Hexadecimal to Decimal

2AF₁₆ = 2×16² + 10×16¹ + 15×16⁰
      = 512 + 160 + 15
      = 687₁₀

Hexadecimal to Binary

Convert each hex digit to 4 binary bits:

2AF₁₆ = 0010 1010 1111₂
        2    A    F

Common Hexadecimal Uses

Memory Addresses:

0x7fff5fbff8c0  // Stack address
0x100000000     // Common base address

Color Codes:

#FF5733  /* RGB: 255, 87, 51 */
#00FF00  /* Pure green */

MAC Addresses:

00:1A:2B:3C:4D:5E

Octal Number System (Base 8)

Octal Basics

Octal uses digits 0-7. Each octal digit represents 3 binary bits.

Unix File Permissions

The most common use of octal is Unix file permissions:

chmod 755 file.sh

Breaking down 755:

  • 7 (111₂) = rwx (read, write, execute) for owner
  • 5 (101₂) = r-x (read, execute) for group
  • 5 (101₂) = r-x (read, execute) for others

Octal Conversion

Octal to Binary:

752₈ = 111 101 010₂
       7   5   2

Octal to Decimal:

752₈ = 7×8² + 5×8¹ + 2×8⁰
     = 448 + 40 + 2
     = 490₁₀

Conversion Algorithms

Universal Conversion Method

To convert from any base to any other base:

  1. Convert source to decimal (intermediate)
  2. Convert decimal to target base

Direct Binary-Hex Conversion

Since 16 = 2⁴, conversion is direct:

Binary → Hex: Group bits in fours from right

1101 0110 1011₂ = D6B₁₆

Hex → Binary: Expand each hex digit to 4 bits

A3F₁₆ = 1010 0011 1111₂

Direct Binary-Octal Conversion

Since 8 = 2³, group bits in threes:

Binary → Octal:

101 110 011₂ = 563₈

Octal → Binary:

274₈ = 010 111 100₂

Code Implementations

JavaScript Implementation

class BaseConverter {
  static toDecimal(value, fromBase) {
    return parseInt(value, fromBase);
  }

  static fromDecimal(decimal, toBase) {
    return decimal.toString(toBase).toUpperCase();
  }

  static convert(value, fromBase, toBase) {
    const decimal = this.toDecimal(value, fromBase);
    return this.fromDecimal(decimal, toBase);
  }

  static toBinary(value, fromBase = 10) {
    return this.convert(value, fromBase, 2);
  }

  static toHex(value, fromBase = 10) {
    return this.convert(value, fromBase, 16);
  }

  static toOctal(value, fromBase = 10) {
    return this.convert(value, fromBase, 8);
  }
}

// Usage examples
console.log(BaseConverter.convert('FF', 16, 10));  // "255"
console.log(BaseConverter.convert('255', 10, 2));  // "11111111"
console.log(BaseConverter.toBinary('A5', 16));     // "10100101"

Python Implementation

class BaseConverter:
    @staticmethod
    def to_decimal(value: str, from_base: int) -> int:
        return int(value, from_base)
    
    @staticmethod
    def from_decimal(decimal: int, to_base: int) -> str:
        if to_base == 2:
            return bin(decimal)[2:]
        elif to_base == 8:
            return oct(decimal)[2:]
        elif to_base == 16:
            return hex(decimal)[2:].upper()
        else:
            # Generic conversion for any base
            if decimal == 0:
                return '0'
            digits = []
            while decimal:
                digits.append('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'[decimal % to_base])
                decimal //= to_base
            return ''.join(reversed(digits))
    
    @staticmethod
    def convert(value: str, from_base: int, to_base: int) -> str:
        decimal = BaseConverter.to_decimal(value, from_base)
        return BaseConverter.from_decimal(decimal, to_base)

# Usage examples
print(BaseConverter.convert('FF', 16, 10))   # 255
print(BaseConverter.convert('255', 10, 2))   # 11111111
print(BaseConverter.convert('777', 8, 16))   # 1FF

Java Implementation

public class BaseConverter {
    public static long toDecimal(String value, int fromBase) {
        return Long.parseLong(value, fromBase);
    }
    
    public static String fromDecimal(long decimal, int toBase) {
        return Long.toString(decimal, toBase).toUpperCase();
    }
    
    public static String convert(String value, int fromBase, int toBase) {
        long decimal = toDecimal(value, fromBase);
        return fromDecimal(decimal, toBase);
    }
    
    public static void main(String[] args) {
        System.out.println(convert("FF", 16, 10));   // 255
        System.out.println(convert("255", 10, 2));   // 11111111
        System.out.println(convert("1010", 2, 16));  // A
    }
}

Go Implementation

package main

import (
    "fmt"
    "strconv"
    "strings"
)

func ToDecimal(value string, fromBase int) (int64, error) {
    return strconv.ParseInt(value, fromBase, 64)
}

func FromDecimal(decimal int64, toBase int) string {
    return strings.ToUpper(strconv.FormatInt(decimal, toBase))
}

func Convert(value string, fromBase, toBase int) (string, error) {
    decimal, err := ToDecimal(value, fromBase)
    if err != nil {
        return "", err
    }
    return FromDecimal(decimal, toBase), nil
}

func main() {
    result, _ := Convert("FF", 16, 10)
    fmt.Println(result)  // 255
    
    result, _ = Convert("255", 10, 2)
    fmt.Println(result)  // 11111111
}

Practical Applications

1. Bit Manipulation

// Check if nth bit is set
function isBitSet(num, n) {
  return (num & (1 << n)) !== 0;
}

// Set nth bit
function setBit(num, n) {
  return num | (1 << n);
}

// Clear nth bit
function clearBit(num, n) {
  return num & ~(1 << n);
}

// Toggle nth bit
function toggleBit(num, n) {
  return num ^ (1 << n);
}

2. IP Address Conversion

def ip_to_binary(ip):
    """Convert IP address to binary representation"""
    octets = ip.split('.')
    binary_octets = [format(int(octet), '08b') for octet in octets]
    return '.'.join(binary_octets)

def ip_to_decimal(ip):
    """Convert IP address to single decimal number"""
    octets = [int(x) for x in ip.split('.')]
    return (octets[0] << 24) + (octets[1] << 16) + (octets[2] << 8) + octets[3]

# Example
print(ip_to_binary('192.168.1.1'))
# 11000000.10101000.00000001.00000001

print(ip_to_decimal('192.168.1.1'))
# 3232235777

3. Color Code Conversion

function hexToRgb(hex) {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16)
  } : null;
}

function rgbToHex(r, g, b) {
  return '#' + [r, g, b]
    .map(x => x.toString(16).padStart(2, '0'))
    .join('')
    .toUpperCase();
}

console.log(hexToRgb('#FF5733'));  // {r: 255, g: 87, b: 51}
console.log(rgbToHex(255, 87, 51)); // #FF5733

4. Unicode and Character Encoding

def char_to_codes(char):
    """Get various representations of a character"""
    code_point = ord(char)
    return {
        'character': char,
        'decimal': code_point,
        'hexadecimal': hex(code_point),
        'binary': bin(code_point),
        'octal': oct(code_point)
    }

print(char_to_codes('A'))
# {'character': 'A', 'decimal': 65, 'hexadecimal': '0x41', 
#  'binary': '0b1000001', 'octal': '0o101'}

Common Pitfalls and Solutions

1. Leading Zeros

// Problem: Leading zeros in octal
const num = 010;  // This is 8 in decimal (octal literal)!

// Solution: Use explicit conversion
const num = parseInt('010', 10);  // 10 in decimal

2. Large Number Precision

// Problem: JavaScript loses precision for large integers
const big = 0x1FFFFFFFFFFFFF;  // Max safe integer

// Solution: Use BigInt for large numbers
const bigNum = BigInt('0x1FFFFFFFFFFFFFF');
console.log(bigNum.toString(2));  // Accurate binary

3. Negative Numbers

# Two's complement representation
def twos_complement(n, bits=8):
    """Get two's complement representation"""
    if n < 0:
        n = (1 << bits) + n
    return format(n, f'0{bits}b')

print(twos_complement(-5, 8))   # 11111011
print(twos_complement(5, 8))    # 00000101

Quick Reference Table

Decimal Binary Octal Hexadecimal
0 0000 0 0
1 0001 1 1
2 0010 2 2
3 0011 3 3
4 0100 4 4
5 0101 5 5
6 0110 6 6
7 0111 7 7
8 1000 10 8
9 1001 11 9
10 1010 12 A
11 1011 13 B
12 1100 14 C
13 1101 15 D
14 1110 16 E
15 1111 17 F
16 10000 20 10
255 11111111 377 FF

Summary

Number base conversion is a fundamental skill for programmers. Key takeaways:

  1. Binary (base 2) is the foundation of all computer operations
  2. Hexadecimal (base 16) provides compact representation of binary data
  3. Octal (base 8) is primarily used for Unix file permissions
  4. Direct conversion between binary, octal, and hex is efficient due to power-of-2 relationships
  5. Understanding two's complement is essential for working with negative numbers

For quick and accurate base conversions, try our Base Converter Tool - it supports conversions between binary, octal, decimal, and hexadecimal with real-time results.