009. Floats
Floating-point numbers are approximations
009. Floats
Aryan wants to show memory usage as a percentage: used / total * 100.
He writes:
def ram_percent(used, total):
return used // total * 100With 3 GB used out of 8 GB total: 3 // 8 = 0, so 0 * 100 = 0%. The monitor shows 0% memory used — completely wrong.
// is floor division: it truncates the fractional part before multiplying. Whenever the numerator is smaller than the denominator, floor division returns 0.
For percentages, averages, ratios — anything that can have a fractional result — you need true division /, which always returns a float.
Fix the physics utility below using the same lesson: // was used where / was needed, silently destroying fractional results.
💡 Fun fact: Python’s float uses the IEEE 754 double-precision standard — the same format used by virtually every programming language and CPU since 1985. This is why 0.1 + 0.2 equals 0.30000000000000004 in Python, JavaScript, C, and Java alike: it is a hardware-level representation issue, not a Python bug.
⚠️ Watch out: Never compare floats with == — use abs(a - b) < 1e-9 instead. Two floats that should be equal mathematically can differ by a tiny rounding error, causing a == b to return False and producing bugs that are extremely hard to reproduce reliably.
🤔 Think about it: If 0.1 + 0.2 is not exactly 0.3 in floating-point, how does your bank calculate your account balance without accumulating rounding errors over millions of transactions?
Learning objectives
- Use / for true (float) division
- Understand that // truncates fractional results
- Compare floats with a tolerance, not ==
Key concepts
- float
- true division
- floating-point precision
Try it
Concept detail
Python’s float uses IEEE 754 double-precision (64-bit). Key facts:
/ (true division) always returns float: 10 / 3 = 3.3333333333333335 // (floor division) truncates toward negative infinity: 10 // 3 = 3, -7 // 2 = -4
The silent bug: floor division of a small numerator by a large denominator returns 0. average_velocity(10, 3) with // returns 3, not 3.333 — a 10% error. For a small enough numerator (distance=2, time=5), // gives 0, losing the result entirely.
Float precision limits: 0.1 + 0.2 is not exactly 0.3 in floating-point arithmetic (it’s 0.30000000000000004). Always compare floats with a tolerance: abs(a - b) < 1e-9 ← correct a == b ← may fail due to rounding
For money or exact decimals, use the decimal module. For scientific computing, use numpy’s float64 with appropriate tolerances.
Solution
def average_velocity(distance, time):
return distance / time
def kinetic_energy(mass, velocity):
return 0.5 * mass * velocity ** 2Tests
def test_velocity_basic():
result = average_velocity(100, 4)
assert result == 25.0
def test_velocity_fractional():
result = average_velocity(10, 3)
assert abs(result - 3.333333) < 0.001
def test_velocity_returns_float():
result = average_velocity(10, 4)
assert isinstance(result, float)
def test_kinetic_energy_basic():
result = kinetic_energy(2, 3)
assert result == 9.0
def test_kinetic_energy_formula():
result = kinetic_energy(10, 4)
assert result == 80.0