Python numbers, explained
Numbers feel simple until an interviewer asks why 0.1 + 0.2 != 0.3, or what -7 // 2
returns. Python's numeric model has a few deliberate design choices — arbitrary-precision
integers, floor division, IEEE-754 floats — that are worth understanding properly.
The built-in numeric types
Python ships three numeric types:
type(42) # <class 'int'> — whole numbers, unbounded
type(3.14) # <class 'float'> — IEEE-754 double precision
type(2 + 3j) # <class 'complex'> — real + imaginary parts
There's also decimal.Decimal and fractions.Fraction in the standard library for exact
decimal and rational arithmetic when floats aren't precise enough.
Integers never overflow
Unlike C or Java, Python int has arbitrary precision — it grows to fit the value,
limited only by memory. There is no INT_MAX.
2 ** 1000 # a 302-digit number, computed exactly
import math
math.factorial(50) # 30414093201713378043612608166064768844377641568960512000000000000
This is why Python is comfortable for cryptography and big-number math without special libraries.
Division: /, //, and %
Python has three division-related operators, and the distinction matters:
7 / 2 # 3.5 — true division, always returns a float
7 // 2 # 3 — floor division, rounds toward negative infinity
7 % 2 # 1 — modulo (remainder)
The subtle part is negatives. Floor division rounds down (toward −∞), not toward zero:
-7 // 2 # -4 (not -3) — floored
-7 % 2 # 1 — the sign follows the divisor
7 % -2 # -1
The invariant always holds: (a // b) * b + (a % b) == a. divmod(a, b) returns both at
once: divmod(-7, 2) → (-4, 1).
Floats and the 0.1 + 0.2 problem
Floats are binary approximations (IEEE-754 doubles). Many decimal fractions can't be represented exactly in binary, so small errors creep in:
0.1 + 0.2 # 0.30000000000000004
0.1 + 0.2 == 0.3 # False
This isn't a Python bug — it's how floating point works everywhere. Don't compare floats
with ==. Instead use a tolerance:
import math
math.isclose(0.1 + 0.2, 0.3) # True
For money and other exact-decimal needs, use Decimal:
from decimal import Decimal
Decimal("0.1") + Decimal("0.2") # Decimal('0.3') — exact
Note you pass a string to Decimal; Decimal(0.1) would inherit the float's error.
Bitwise operators
For integers, Python provides the usual bit-level operators:
5 & 3 # 1 — AND
5 | 3 # 7 — OR
5 ^ 3 # 6 — XOR
~5 # -6 — NOT (two's complement: ~x == -x - 1)
1 << 4 # 16 — left shift (multiply by 2**4)
32 >> 2 # 8 — right shift
These work on Python's arbitrary-precision integers too, so shifting never overflows.
Exponentiation and other helpers
2 ** 10 # 1024 — power
pow(2, 10, 1000) # 24 — (2**10) % 1000, computed efficiently
abs(-5) # 5
round(2.675, 2) # 2.67 — banker's rounding + float imprecision, careful!
round uses banker's rounding (round-half-to-even), and combined with float
imprecision it can surprise you — another reason to reach for Decimal when exactness
matters.
Recap
Python has int (arbitrary precision — no overflow), float (IEEE-754 doubles), and
complex. True division / always yields a float; floor division // rounds toward
negative infinity, so -7 // 2 is -4, and % takes the sign of the divisor. Floats are
binary approximations, so 0.1 + 0.2 != 0.3 — compare with math.isclose and use
decimal.Decimal("...") for exact decimal arithmetic. divmod, pow(x, y, mod), and the
bitwise operators round out the toolkit.