Numbers & Precision in Python
Master Python's dual-nature numeric system. From the "Infinite Tape" of arbitrary-precision integers to the tricky world of IEEE 754 floating-point binaries, learn how to calculate with confidence.
Numbers seem simple. We use them every day. But inside a computer, numbers are a minefield of trade-offs between Speed, Memory, and Precision.
Most programming languages (like C or Java) strictly tie numbers to hardware limits (32-bit or 64-bit). If you try to count too high, your number "overflows" and wraps around to a negative value. Python is different. It prioritizes User Experience over raw hardware mapping.
What You'll Learn
- The Infinite Tape: How Python integers grow forever (Arbitrary Precision).
- The Binary Trap: Why
0.1 + 0.2 != 0.3(IEEE 754 Deep Dive). - Bitwise Magic: Manipulating individual bits with
&,|, and^. - Complex Numbers: Using real and imaginary components for engineering.
- Financial Math: Using the
Decimalmodule for exact currency calculations. - Formatting Mastery: Controlling significant digits with f-strings.
The Two Worlds of Python Numbers
To write bug-free numerical code, you need two distinct mental models.
🧩 Analogy: The Tape vs. The Slidewire
Imagine a measuring tape that magically grows longer whenever you need it. You can write a number with 5 digits, or 5,000 digits. It will always be exact. It never rounds, and it never runs out of space (until your RAM fills up).
Imagine writing numbers on a small index card. You only have space for about 16 digits. If the number is too long (like Pi), you mistakenly cut off the end. This creates rounding errors.
1. Integers: Arbitrary Precision
In C, an integer is a fixed box (usually 4 bytes). In Python, an integer is a dynamic object. This allows you to calculate numbers larger than the number of atoms in the universe.
# A Googol (1 followed by 100 zeros)
googol = 10 ** 100
print(googol)
# Output: 100000... (lots of zeros) ...0000
# Factorials explode in size rapidly
import math
huge_num = math.factorial(100)
print(f"Digits in 100!: {len(str(huge_num))}")
# Output: Digits in 100!: 158
# C-style Overflow? Doesn't exist.
x = 2 ** 63 - 1 # Logic limit for 64-bit integers
print(x + 1) # Python just expands the memory allocation.Performance Note
This magic comes at a cost. A standard C integer takes 4 bytes. A Python integer object takes at least 28 bytes plus size of the digits.
Is it slow? Yes, for high-performance number crunching (like video games or matrix multiplication), pure Python integers are too slow. That's why we use libraries like NumPy (which brings C-style fixed-size integers back to Python).
2. Bitwise Operations: The Hardware Level
Integers aren't just numbers; they are sequences of bits. Python allows you to manipulate these bits directly, which is crucial for cryptography, networking, and permissions systems.
| Operator | Name | Description | Example (0b101, 0b001) |
|---|---|---|---|
& | AND | Bits are 1 if BOTH are 1 | 5 & 1 -> 1 |
| | OR | Bits are 1 if EITHER is 1 | 5 | 1 -> 5 |
^ | XOR | Bits are 1 if DIFFERENT | 5 ^ 1 -> 4 |
<< | Left Shift | Shift bits left (Multiply by 2) | 5 << 1 -> 10 |
>> | Right Shift | Shift bits right (Divide by 2) | 5 >> 1 -> 2 |
# Permissions Mockup
READ = 0b100 # 4
WRITE = 0b010 # 2
EXEC = 0b001 # 1
# My permissions: Read (4) + Execute (1) = 5
my_perms = READ | EXEC
# Check if I have WRITE permissions
if my_perms & WRITE:
print("Access Granted")
else:
print("Access Denied") # Prints Denied3. Floats: The Binary Binary Trap
Python float uses the IEEE 754 standard (Double Precision). It stores numbers using binary scientific notation:Sign * Mantissa * 2^Exponent.
The problem is that humans count in Base-10, but computers count in Base-2. Just as 1/3 cannot be written exactly in Base-10 (0.3333...),0.1 cannot be written exactly in Base-2.
# The famous precision error
print(0.1 + 0.2)
# Output: 0.30000000000000004
# Why? Let's look at the true formatting for 18 digits
print(f"{0.1:.18f}")
# Output: 0.100000000000000006
# This means equality checks FAIL
if 0.1 + 0.2 == 0.3:
print("Math works!")
else:
print("Math is broken?") # This prints!Solution: math.isclose()
Never compare floats directly. Always ask: "Are these close enough?"
import math
a = 0.1 + 0.2
b = 0.3
# Check if they are close within a small tolerance (epsilon)
if math.isclose(a, b):
print("Math works again!")4. The Decimal Module: Exact Math
If you are building a banking app, "close enough" isn't good enough. You can't lose a penny due to rounding. Enter the Decimal type. It stores numbers as decimal digits (Base-10), exactly as humans do.
from decimal import Decimal
# âš ï¸ WRONG: Creating Decimal from Float (inherits the error)
bad = Decimal(0.1)
print(bad)
# Output: 0.10000000000000000555...
# ✅ CORRECT: Creating Decimal from String
price = Decimal("19.99")
tax = Decimal("0.08")
total = price * (1 + tax)
print(total)
# Output: 21.5892 (Exact)5. Complex Numbers: Engineering Power
Python is one of the few languages with built-in support for Complex Numbers, widely used in Electrical Engineering and Physics. They consist of a real part and an imaginary part (suffix j).
# Creating complex numbers
z = 3 + 4j
print(type(z)) # <class 'complex'>
# Attributes
print(z.real) # 3.0
print(z.imag) # 4.0
# Conjugate
print(z.conjugate()) # (3-4j)
# Arithmetic works natively
z2 = 1 - 1j
print(z + z2) # (4+3j)Formatting: Making Numbers Pretty
Often you have a float with 10 decimal places, but you only want to display 2. Fast-Strings (f-strings) are the modern way to handle this.
| Format Code | Description | Example Input | Output |
|---|---|---|---|
:.2f | Fixed point (2 decimals) | 3.14159 | "3.14" |
:, | Comma separator | 10000 | "10,000" |
:.0% | Percentage | 0.25 | "25%" |
:03d | Zero padding (integers) | 5 | "005" |
pi = 3.14159265
revenue = 12500000.50
# Combining formats: Comma separator AND 2 decimal places
print(f"Revenue: $\{revenue:,.2f}")
# Output: Revenue: $12,500,000.50
# Percentage
accuracy = 0.985
print(f"Accuracy: {accuracy:.1%}")
# Output: Accuracy: 98.5%Computer Science: Number Bases
Sometimes you need to speak the machine's native language. Python provides literals for Binary, Octal, and Hexadecimal.
# 0b = Binary (Base-2)
x = 0b1010
print(f"Binary 1010 is {x} in Decimal")
# 0x = Hexadecimal (Base-16)
# Used heavily in colors (#FF00FF) and memory addresses
color = 0xFF
print(f"Hex FF is {color} in Decimal")
# Underscores for readability (Python 3.6+)
# Computers ignore them, but humans love them.
speed_of_light = 299_792_458
bytes_in_gb = 1_073_741_824Best Practices & Takeaways
✅ Do
- Use
math.isclose()for float comparisons. - Use
from decimal import Decimalfor Money. - Use underscores (
1_000_000) for long numbers. - Use f-strings (
:.2f) for display formatting. - Use Bitwise operators only when explicitly manipulating flag bits.
⌠Don't
- Don't use
floatfor banking apps. - Don't rely on
round()for precise rounding logic (it has quirks). - Don't compare
x == 3.3unless you know exactly what you are doing.