Working with Numbers and Arithmetic Operators

Python offers seven arithmetic operators: + (addition), - (subtraction), * (multiplication), / (true division, always returns a float), // (floor division, returns an int if both operands are ints), % (modulus, the remainder), and ** (exponentiation). They follow the mathematical precedence you already know: ** first, then unary sign, then * / // %, then + -. When in doubt, add parentheses — they cost nothing and make intent explicit.

The crucial distinction compared with many languages is / vs //. In Python 3, 5 / 2 is 2.5 — even if both operands are integers, true division returns a float. Use // when you want integer division that rounds toward negative infinity: 7 // 2 is 3, and importantly -7 // 2 is -4 (not -3). The modulus follows the same rule so that a == (a // b) * b + (a % b) always holds.

All arithmetic operators have augmented-assignment forms: x += 1, total *= 2, n //= 10. For built-in numbers these are just shortcuts, but for mutable types (for example, lists) they can modify the object in place, which matters when the same list is referenced elsewhere. Keep the shortcut form for counters and accumulators; it reads well and avoids repeating the variable name.

The math module fills the gaps: math.sqrt, math.floor, math.ceil, math.log, the trigonometric functions, math.pi and math.inf. For numeric work beyond basic arithmetic, NumPy is the de-facto standard, but the standard library is enough for most scripts. The built-in round() performs banker's rounding (round half to even), which surprises many newcomers: round(0.5) is 0, not 1. Use math.floor/math.ceil when you need a specific direction.

For money and other quantities where every cent counts, floating-point is the wrong tool — its binary representation cannot express decimal 0.1 exactly. Use decimal.Decimal for exact decimal arithmetic, and fractions.Fraction when you need exact rational numbers. Both modules are a drop-in replacement for the arithmetic operators but store values in a way that matches human expectations.

Augmented assignment and numeric coercion

Expressions mix types predictably: an int combined with a float becomes a float; a bool in arithmetic is treated as 0 or 1. Conversion is explicit in every other direction: int(3.9) is 3 (truncation toward zero), float(2) is 2.0. Understanding these rules makes it easy to read expressions without mentally tracking types.

Floor division, modulus, and negative numbers

Floor division and modulus are the engine of every "every Nth item" or "wrap around after" pattern. Walking a circular buffer of length n is buf[i % n]; splitting a total of seconds into minutes and seconds is m, s = divmod(total, 60). divmod(a, b) returns a tuple (a // b, a % b) in a single call.

These tools cover arithmetic from simple counters to floating-point analysis.

ToolPurpose
+ - * / // % **
operators
Arithmetic operators with mathematical precedence.
abs()
built-in
Absolute value; works for int, float and Decimal.
divmod()
built-in
Returns (a // b, a % b) in a single call.
pow()
built-in
Exponentiation; pow(x, y, m) computes (x**y) % m efficiently.
round()
built-in
Banker's rounding to a given number of decimals.
math.sqrt()
function
Square root; prefers floats, raises for negatives.
math.floor() / math.ceil()
functions
Round down or up regardless of sign.
decimal.Decimal
class
Exact decimal arithmetic for money-like quantities.

Working with Numbers and Arithmetic Operators code example

The example computes a price breakdown with taxes and rounding, then splits a total of seconds into hours, minutes and seconds using divmod.

# Lesson: Working with Numbers and Arithmetic Operators
# Goal: show true vs floor division, %/divmod, and why Decimal is right for money.
from decimal import Decimal, ROUND_HALF_UP
from math import ceil


TAX_RATE = Decimal("0.19")  # 19 % VAT, exact


def price_with_tax(net: Decimal) -> Decimal:
    '''Return the gross price rounded to two decimals (HALF_UP).'''
    gross = net * (1 + TAX_RATE)
    return gross.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)


def split_seconds(total: int) -> tuple[int, int, int]:
    '''Break `total` seconds into (hours, minutes, seconds).'''
    hours, remainder = divmod(total, 3600)
    minutes, seconds = divmod(remainder, 60)
    return hours, minutes, seconds


# --- main script ---------------------------------------------------------
cart = [Decimal("9.99"), Decimal("1.50"), Decimal("23.00")]
net_total = sum(cart)
gross_total = price_with_tax(net_total)
print(f"net:   {net_total}")
print(f"gross: {gross_total}")

# counter pattern with augmented assignment
batch_size = 50
items = 237
batches = ceil(items / batch_size)
print(f"{items} items -> {batches} batches of up to {batch_size}")

h, m, s = split_seconds(3_723)
print(f"3723s = {h:02d}:{m:02d}:{s:02d}")

# true vs floor division on negatives
print(f"-7 / 2  = {-7 / 2}")
print(f"-7 // 2 = {-7 // 2}")
print(f"-7 % 2  = {-7 % 2}")

Things to notice while reading:

1) Decimal prevents rounding drift that float would introduce.
2) ceil(items / batch_size) gives the number of full + partial batches.
3) divmod produces two values at once, removing repeated arithmetic.
4) Floor division of a negative rounds toward -infinity.

Two snippets: one for floor division patterns, one for exponentiation.

# Example A: money arithmetic that stays exact
from decimal import Decimal
subtotal = Decimal("19.99") + Decimal("0.01")
print(subtotal == Decimal("20.00"))  # -> True
# With floats the same test would print False.

# Example B: efficient modular exponentiation
# pow(base, exp, mod) is much faster than (base ** exp) % mod for big numbers.
print(pow(7, 256, 13))

These assertions codify the distinctions that matter.

assert 7 / 2 == 3.5                # true division always returns float
assert 7 // 2 == 3                 # floor division stays int
assert -7 // 2 == -4               # floor rounds toward -inf
assert divmod(17, 5) == (3, 2)
assert price_with_tax(Decimal("100")) == Decimal("119.00")

Running the script prints:

net:   34.49
gross: 41.04
237 items -> 5 batches of up to 50
3723s = 01:02:03
-7 / 2  = -3.5
-7 // 2 = -4
-7 % 2  = 1