Skip to content

Binary to Decimal Converter

Abstract

Converting numbers between bases is the bridge between how we count (base 10) and how computers count (base 2). In this project you build a Python converter that goes both ways between binary and decimal, then extend it to handle octal, hexadecimal, arbitrary bases (2–36), negative numbers via two’s complement, and a peek at how floating-point numbers are stored in IEEE 754. Along the way you implement both the “use the built-in” version and the “from scratch” algorithm so you understand what int(s, 2)int(s, 2) and bin()bin() actually do.

You will learn:

  • The mechanics of positional number systems.
  • Python’s int(string, base)int(string, base) and bin()bin() / oct()oct() / hex()hex().
  • How to convert any base in pure Python.
  • Two’s complement for representing negative integers.
  • IEEE 754 single-precision float layout.
  • Input validation and friendly error reporting.

Why Bases Matter

  • Base 2 (binary) — the physical layer of every digital computer (transistors are on/off).
  • Base 8 (octal) — Unix file permissions (chmod 755chmod 755).
  • Base 10 (decimal) — humans.
  • Base 16 (hex) — RGB colors (#ff8000#ff8000), memory addresses, MAC addresses, byte dumps.

Prerequisites

  • Python 3.6 or above.
  • A text editor or IDE.
  • Comfort with input()input(), if/elif/elseif/elif/else, and basic loops.

Getting Started

Create the project

  1. Create folder binary-decimal-converterbinary-decimal-converter.
  2. Inside, create binary_to_decimal.pybinary_to_decimal.py.

Write the code

Binary to DecimalSource
Binary to Decimal
# Binary to Decimal Conveter
 
print("Binary to Decimal Conveter")
print("Choose one of the following options:")
print("1. Convert a binary number to a decimal number")
print("2. Convert a decimal number to a binary number")
print("3. Exit")
 
option = int(input("Enter your option: "))
if option == 1:
    binary = input("Enter a binary number: ")
    decimal = int(binary, 2)
    print("The decimal value of", binary, "is", decimal)
elif option == 2:
    decimal = int(input("Enter a decimal number: "))
    binary = bin(decimal)
    print("The binary value of", decimal, "is", binary)
elif option == 3:
    exit()
Binary to Decimal
# Binary to Decimal Conveter
 
print("Binary to Decimal Conveter")
print("Choose one of the following options:")
print("1. Convert a binary number to a decimal number")
print("2. Convert a decimal number to a binary number")
print("3. Exit")
 
option = int(input("Enter your option: "))
if option == 1:
    binary = input("Enter a binary number: ")
    decimal = int(binary, 2)
    print("The decimal value of", binary, "is", decimal)
elif option == 2:
    decimal = int(input("Enter a decimal number: "))
    binary = bin(decimal)
    print("The binary value of", decimal, "is", binary)
elif option == 3:
    exit()

Run it

command
C:\Users\Your Name\binary-decimal-converter> python binary_to_decimal.py
Binary ↔ Decimal Converter
1. Binary → Decimal
2. Decimal → Binary
3. Exit
Choice: 1
Binary: 1101
1101= 13₁₀
command
C:\Users\Your Name\binary-decimal-converter> python binary_to_decimal.py
Binary ↔ Decimal Converter
1. Binary → Decimal
2. Decimal → Binary
3. Exit
Choice: 1
Binary: 1101
1101= 13₁₀

Step-by-Step Explanation

1. Using built-ins (the right answer for production)

builtins.py
# Binary string → decimal int
decimal = int("1101", 2)        # 13
 
# Decimal int → binary string (with '0b' prefix)
binary = bin(13)                # '0b1101'
 
# Strip the prefix if you want just the digits
binary_clean = bin(13)[2:]      # '1101'
 
# Also available:
hexadecimal = hex(13)           # '0xd'
octal       = oct(13)           # '0o15'
builtins.py
# Binary string → decimal int
decimal = int("1101", 2)        # 13
 
# Decimal int → binary string (with '0b' prefix)
binary = bin(13)                # '0b1101'
 
# Strip the prefix if you want just the digits
binary_clean = bin(13)[2:]      # '1101'
 
# Also available:
hexadecimal = hex(13)           # '0xd'
octal       = oct(13)           # '0o15'

int(s, base)int(s, base) accepts any base from 2 to 36. Above 10, digits use letters a..za..z (case-insensitive).

2. Menu with validation

menu.py
def main():
    while True:
        print("\n1. Binary → Decimal  2. Decimal → Binary  3. Exit")
        choice = input("> ").strip()
        if choice == "1":
            raw = input("Binary: ").strip()
            if not all(c in "01" for c in raw) or not raw:
                print("Use only 0s and 1s."); continue
            print(f"{raw}₂ = {int(raw, 2)}₁₀")
        elif choice == "2":
            raw = input("Decimal: ").strip()
            try:
                n = int(raw)
            except ValueError:
                print("Not an integer."); continue
            print(f"{n}₁₀ = {bin(n)[2:]}₂")
        elif choice == "3":
            break
        else:
            print("Invalid choice.")
menu.py
def main():
    while True:
        print("\n1. Binary → Decimal  2. Decimal → Binary  3. Exit")
        choice = input("> ").strip()
        if choice == "1":
            raw = input("Binary: ").strip()
            if not all(c in "01" for c in raw) or not raw:
                print("Use only 0s and 1s."); continue
            print(f"{raw}₂ = {int(raw, 2)}₁₀")
        elif choice == "2":
            raw = input("Decimal: ").strip()
            try:
                n = int(raw)
            except ValueError:
                print("Not an integer."); continue
            print(f"{n}₁₀ = {bin(n)[2:]}₂")
        elif choice == "3":
            break
        else:
            print("Invalid choice.")

Two validation guards — character set for binary, int()int() for decimal — and friendly error messages.

Doing It By Hand

Binary → Decimal

bin2dec.py
def bin_to_dec(s: str) -> int:
    total = 0
    for digit in s:
        total = total * 2 + int(digit)        # Horner's method
    return total
bin2dec.py
def bin_to_dec(s: str) -> int:
    total = 0
    for digit in s:
        total = total * 2 + int(digit)        # Horner's method
    return total

Trace for "1101""1101":

text
start    total = 0
'1'      total = 0*2 + 1 = 1
'1'      total = 1*2 + 1 = 3
'0'      total = 3*2 + 0 = 6
'1'      total = 6*2 + 1 = 13
text
start    total = 0
'1'      total = 0*2 + 1 = 1
'1'      total = 1*2 + 1 = 3
'0'      total = 3*2 + 0 = 6
'1'      total = 6*2 + 1 = 13

That single multiply-and-add idiom is Horner’s method and works for any base (replace 22 with basebase).

Decimal → Binary

dec2bin.py
def dec_to_bin(n: int) -> str:
    if n == 0: return "0"
    if n < 0:  return "-" + dec_to_bin(-n)
    out = []
    while n:
        out.append(str(n & 1))                # last bit
        n >>= 1                               # shift right
    return "".join(reversed(out))
dec2bin.py
def dec_to_bin(n: int) -> str:
    if n == 0: return "0"
    if n < 0:  return "-" + dec_to_bin(-n)
    out = []
    while n:
        out.append(str(n & 1))                # last bit
        n >>= 1                               # shift right
    return "".join(reversed(out))
  • n & 1n & 1 extracts the least-significant bit (0 or 1).
  • n >>= 1n >>= 1 shifts right, dropping that bit.
  • Building backwards then reversing avoids inefficient string prepend.

Arbitrary-Base Conversions

any_base.py
DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"
 
def to_base(n: int, base: int) -> str:
    if not 2 <= base <= 36:
        raise ValueError("base must be 2..36")
    if n == 0: return "0"
    sign = "-" if n < 0 else ""
    n = abs(n)
    out = []
    while n:
        out.append(DIGITS[n % base])
        n //= base
    return sign + "".join(reversed(out))
 
def from_base(s: str, base: int) -> int:
    s = s.lower().strip()
    sign = 1
    if s.startswith("-"): sign, s = -1, s[1:]
    n = 0
    for ch in s:
        digit = DIGITS.index(ch)
        if digit >= base:
            raise ValueError(f"'{ch}' is not valid in base {base}")
    return sign * sum(DIGITS.index(c) * (base ** i)
                      for i, c in enumerate(reversed(s)))
any_base.py
DIGITS = "0123456789abcdefghijklmnopqrstuvwxyz"
 
def to_base(n: int, base: int) -> str:
    if not 2 <= base <= 36:
        raise ValueError("base must be 2..36")
    if n == 0: return "0"
    sign = "-" if n < 0 else ""
    n = abs(n)
    out = []
    while n:
        out.append(DIGITS[n % base])
        n //= base
    return sign + "".join(reversed(out))
 
def from_base(s: str, base: int) -> int:
    s = s.lower().strip()
    sign = 1
    if s.startswith("-"): sign, s = -1, s[1:]
    n = 0
    for ch in s:
        digit = DIGITS.index(ch)
        if digit >= base:
            raise ValueError(f"'{ch}' is not valid in base {base}")
    return sign * sum(DIGITS.index(c) * (base ** i)
                      for i, c in enumerate(reversed(s)))

Now to_base(255, 16)to_base(255, 16)"ff""ff", from_base("ff", 16)from_base("ff", 16)255255. The exact same algorithm handles base-3, base-7, base-32, base-36.

Negative Numbers and Two’s Complement

Computers represent signed integers as two’s complement. For an 8-bit number:

  • Positive 5 → 0000 01010000 0101.
  • Negative 5 → invert bits, add 1 → 1111 10111111 1011.
twos.py
def to_twos_complement(n: int, bits: int = 8) -> str:
    if n < 0:
        n = (1 << bits) + n               # wrap into range
    return format(n, f"0{bits}b")
 
def from_twos_complement(s: str) -> int:
    bits = len(s)
    n = int(s, 2)
    return n - (1 << bits) if s[0] == "1" else n
 
print(to_twos_complement(-5, 8))    # 11111011
print(from_twos_complement("11111011"))  # -5
twos.py
def to_twos_complement(n: int, bits: int = 8) -> str:
    if n < 0:
        n = (1 << bits) + n               # wrap into range
    return format(n, f"0{bits}b")
 
def from_twos_complement(s: str) -> int:
    bits = len(s)
    n = int(s, 2)
    return n - (1 << bits) if s[0] == "1" else n
 
print(to_twos_complement(-5, 8))    # 11111011
print(from_twos_complement("11111011"))  # -5

This is exactly how a C int8_tint8_t works.

IEEE 754 Float Layout

Python’s structstruct module lets you peek at how 32-bit floats are stored:

ieee754.py
import struct
bits = struct.pack(">f", 3.14)        # big-endian float
binary = "".join(f"{b:08b}" for b in bits)
print(binary)
# 01000000010010001111010111000011
# sign: 0, exponent: 10000000 (=128 → bias-adjusted 1),
# mantissa: 10010001111010111000011
ieee754.py
import struct
bits = struct.pack(">f", 3.14)        # big-endian float
binary = "".join(f"{b:08b}" for b in bits)
print(binary)
# 01000000010010001111010111000011
# sign: 0, exponent: 10000000 (=128 → bias-adjusted 1),
# mantissa: 10010001111010111000011

This is the layout every desktop CPU uses. It explains why 0.1 + 0.2 != 0.30.1 + 0.2 != 0.3 in every language with IEEE 754 floats.

Common Mistakes

ProblemCauseFix
ValueError: invalid literal for int()ValueError: invalid literal for int()Non-binary characters in inputValidate with all(c in "01" for c in s)all(c in "01" for c in s)
bin(13)bin(13) returns '0b1101''0b1101' not '1101''1101'The 0b0b prefix is informativeSlice [2:][2:]
Manual int(digit) * 2**iint(digit) * 2**i is O(n²) string-wiseBad algorithmUse Horner: total = total * base + dtotal = total * base + d
Negative numbers print as -0b101-0b101Built-in bin()bin() includes the signEither accept it, or build your own
Leading zeros lostNumbers do not preserve formatPad: format(n, "08b")format(n, "08b")
int(s, 0)int(s, 0) infers wrong base00 means “guess from prefix” — 0b0b, 0o0o, 0x0xPass an explicit base

Variations to Try

1. Add octal and hex

Extend the menu with Hex → DecimalHex → Decimal, Decimal → OctalDecimal → Octal, etc.

2. Conversion history

Print each conversion plus a timestamp; export to CSV.

3. Batch mode

Read a list of numbers from a file; emit a converted column.

4. CLI flags

cli
python convert.py 255 --from 10 --to 16    # → ff
python convert.py ff  --from 16 --to 2     # → 11111111
cli
python convert.py 255 --from 10 --to 16    # → ff
python convert.py ff  --from 16 --to 2     # → 11111111

5. GUI version

Tkinter with two big text boxes and base dropdowns. Type in either box; the other updates live.

6. Bitwise visualizer

For each step of the decimal→binary algorithm, show the running value, the bit being extracted, and the resulting binary so far. Great for classrooms.

7. Fractional binary

Extend to fractions: 0.6250.6250.1010.101. Loop value *= 2value *= 2; integer part is the next bit.

8. Two’s-complement signed converter

Use the function above; ask the user how many bits.

9. Color picker

Parse #ff8000#ff8000(255, 128, 0)(255, 128, 0) in RGB.

10. Web tool

A Flask form (see Basic Web Server) that converts on submit.

Real-World Applications

  • Networking — IPv4 192.168.1.1192.168.1.1 to its 32-bit binary representation, subnet calculations.
  • Color manipulation#rrggbb#rrggbb ↔ tuples of decimal.
  • Unix permissionschmod 755chmod 755 is octal rwxr-xr-xrwxr-xr-x.
  • Reverse engineering — interpreting hex dumps and memory addresses.
  • Cryptography — XOR, bit rotations, hex-encoded keys.
  • Embedded programming — register values are hex; bit fields matter.

Educational Value

  • Positional number systems — the most fundamental abstraction in computing.
  • int(s, base)int(s, base) — one of Python’s most underused built-ins.
  • Horner’s method — fewer multiplications than digit * base ** idigit * base ** i.
  • Bitwise operators&&, ||, ^^, <<<<, >>>>.
  • Two’s complement — the actual representation of signed integers.

Next Steps

  • Extend to octal and hex.
  • Implement to_baseto_base / from_basefrom_base for arbitrary bases.
  • Add two’s complement handling.
  • Build a GUI with live conversion as the user types.
  • Read about IEEE 754 to understand why 0.1 + 0.2 != 0.30.1 + 0.2 != 0.3.

Try it here

Click any bit to flip it. Each 11 contributes its place value (128, 64, 32, …), and the total is the decimal number — the same math your code does:

sketch Flip the bits p5.js
Click a bit to toggle it. Each 1 adds its place value; the total is the decimal number.

Conclusion

You built a converter both ways using built-ins, then implemented the math by hand so the int(s, 2)int(s, 2) and bin(n)bin(n) calls stopped looking like magic. The same algorithms power every hex dump, color picker, and networking calculator you have ever used. Full source on GitHub. Find more algorithm projects on Python Central Hub.

If this helped you, consider buying me a coffee ☕

Buy me a coffee

Was this page helpful?

Let us know how we did