Python

Python Math Operators | Complete Guide

A clear guide to Python's arithmetic operators, precedence, augmented assignment, int vs float, and the math module — with correct examples.

By InventiveHQ Team

Python's math operators are the seven arithmetic symbols +, -, *, /, //, %, and **, used for addition, subtraction, multiplication, true division, floor division, modulo (remainder), and exponentiation. The three behaviors that catch people out are that / always returns a float in Python 3 (6 / 3 is 2.0), that % takes the sign of the divisor (-7 % 2 is 1), and that round() uses banker's rounding (round(2.5) is 2). Operator precedence follows PEMDAS, with ** binding tightest and being right-associative.

That is the summary an AI Overview would hand you. What it can't show you is why those rules bite — the diagrams below trace how precedence actually resolves an expression and how floor division and modulo split a negative number, and the symptom-to-fix table maps the exact error messages and wrong answers you'll hit to their causes. This guide covers all of it with correct, runnable examples.

Python operator precedence resolving 1 + 2 * 3 ** 2 A step diagram showing that exponentiation runs first, then multiplication, then addition, evaluating 1 + 2 * 3 ** 2 to 19. Precedence resolves inside-out expression: 1 + 2 * 3 ** 2 1. Exponent ** 3 ** 2 = 9 1 + 2 * 9 2. Multiply * 2 * 9 = 18 1 + 18 3. Add + 1 + 18 = 19 result

final answer 19 left-to-right guess (1+2)*3**2 = 81 is wrong

The Arithmetic Operators

Python has seven core arithmetic operators:

OperatorNameExampleResult
+Addition1 + 23
-Subtraction3 - 21
*Multiplication2 * 36
/True division6 / 32.0
//Floor division5 // 22
%Modulo (remainder)5 % 21
**Exponentiation2 ** 38

Which operator should I use?

The seven operators overlap in ways that cause real bugs. This table maps a goal to the right tool and the trap to avoid:

Your goalUseNot thisWhy
Exact decimal result (e.g. average)//// keeps the fraction as a float
Whole-number quotient (pages, rows)//int(a / b)// avoids float rounding on huge ints
Remainder / "every Nth" / wrap-around%manual subtraction% handles negatives predictably
Both quotient and remainderdivmod(a, b)two separate opsone call, guaranteed consistent
Powers and roots**math.pow** keeps int results; math.pow is always float
Money / precise decimalsdecimal.Decimalfloatfloats can't represent 0.1 exactly

The first surprise: in Python 3, the / operator always returns a float, even when the division is exact.

print(6 / 3)    # 2.0  (a float, not 2)
print(7 / 2)    # 3.5
print(type(6 / 3))  # <class 'float'>

Floor Division and Modulo

Floor division (//) divides and rounds the result down toward negative infinity, returning an int when both operands are integers. The modulo operator (%) gives the remainder.

print(7 // 2)   # 3
print(7 % 2)    # 1

The catch is how these behave with negative numbers. Floor division rounds toward negative infinity (not toward zero), and in Python the result of % always takes the sign of the divisor:

print(-7 // 2)  # -4  (rounds down, not -3)
print(-7 % 2)   #  1  (sign matches the divisor, 2)
print(7 % -2)   # -1  (sign matches the divisor, -2)

A handy related built-in is divmod(), which returns both the quotient and remainder at once: divmod(17, 5) gives (3, 2).

The rule that keeps // and % consistent is the identity (a // b) * b + (a % b) == a. Because Python rounds the quotient down and forces the remainder to match the divisor's sign, the two operators always reconstruct the original number. The diagram below traces it for -7:

How Python splits -7 divided by 2 with floor division and modulo A diagram showing -7 // 2 rounds down to -4 and -7 % 2 is 1, so -4 times 2 plus 1 equals -7. -7 split by // and % -7 // 2 -4 rounds DOWN (not -3) -7 % 2 1 sign of divisor (+) check -4·2 + 1 = -7 ✓ (a // b) * b + (a % b) == a holds for every sign
Advertisement

Exponentiation and Roots

Use ** to raise a number to a power. To compute roots, raise to a fractional exponent:

print(2 ** 3)        # 8
print(5 ** 2)        # 25
print(9 ** 0.5)      # 3.0   (square root)
print(27 ** (1/3))   # 3.0   (cube root)

In Python 3, 1/3 is already a float, so 27 ** (1/3) works as expected — you no longer need the old 1/3.0 workaround that was required in Python 2.

Operator Precedence and Parentheses

Python evaluates operators in a fixed order, similar to the PEMDAS rule from math class: parentheses first, then exponents, then multiplication/division/floor-division/modulo, then addition/subtraction.

print(1 + 2 * 3)    # 7  (multiplication happens first)
print((1 + 2) * 3)  # 9  (parentheses force addition first)
print(2 ** 3 ** 2)  # 512  (** is right-associative: 2 ** 9)

Note that ** is right-associative, so 2 ** 3 ** 2 is 2 ** (3 ** 2), which equals 512, not 64. When precedence isn't obvious at a glance, add parentheses — they cost nothing and make intent clear to the next reader.

Augmented Assignment

Augmented assignment operators combine an operation with assignment, updating a variable in place. They are shorthand and improve readability.

x = 10
x += 5    # same as x = x + 5
print(x)  # 15

x -= 3    # x = x - 3
print(x)  # 12

x *= 2    # x = x * 2
print(x)  # 24

x //= 5   # x = x // 5
print(x)  # 4

x **= 2   # x = x ** 2
print(x)  # 16

Every arithmetic operator has an augmented form: +=, -=, *=, /=, //=, %=, and **=.

Integers vs. Floats

Python automatically picks a numeric type. Whole numbers are int, and numbers with a decimal point are float. Operators promote to float when needed:

print(4 + 2)      # 6     (int + int -> int)
print(4 + 2.0)    # 6.0   (int + float -> float)
print(10 / 2)     # 5.0   (/ always produces a float)
print(10 // 3)    # 3     (int floor division stays int)

Python integers have arbitrary precision — they grow as large as memory allows, with no overflow:

print(2 ** 100)   # 1267650600228229401496703205376

Common Pitfalls

Most math-operator bugs come from a small set of surprises. Use this symptom-to-fix table as a fast lookup before reading the detail below:

Symptom you seeCauseFix
6 / 3 gives 2.0 where you wanted 2/ is always float divisionUse // for an int quotient
0.1 + 0.2 == 0.3 is FalseBinary float can't store 0.1 exactlymath.isclose(a, b) or the decimal module
-7 // 2 is -4, expected -3// rounds toward negative infinityExpected behavior; use int(-7 / 2) to truncate toward zero
-7 % 2 is 1, expected -1% takes the sign of the divisorExpected in Python; use math.fmod for C-style sign
round(2.5) is 2, expected 3Banker's rounding (round-half-to-even)Use math.ceil, or decimal with ROUND_HALF_UP
2 ** 3 ** 2 is 512, expected 64** is right-associativeAdd parentheses: (2 ** 3) ** 2
ZeroDivisionErrorDivisor evaluated to 0Guard with if divisor != 0 before dividing

Floating-point imprecision

Floats are stored in binary and cannot represent every decimal exactly, which leads to tiny rounding errors:

print(0.1 + 0.2)            # 0.30000000000000004
print(0.1 + 0.2 == 0.3)     # False

This is not a Python bug — it affects nearly every programming language. When comparing floats, test that they're close rather than exactly equal:

import math
print(math.isclose(0.1 + 0.2, 0.3))  # True

For exact decimal math (money, for example), use the decimal module instead of floats.

Division by zero

Dividing by zero raises a ZeroDivisionError rather than returning infinity:

print(10 / 0)   # ZeroDivisionError: division by zero
print(10 % 0)   # ZeroDivisionError: integer modulo by zero

Guard against it when the divisor comes from user input or external data:

divisor = 0
if divisor != 0:
    result = 10 / divisor
else:
    result = None

round() uses banker's rounding

Python's built-in round() uses round-half-to-even (banker's rounding), so a value exactly halfway between two integers rounds toward the nearest even number:

print(round(0.5))   # 0  (not 1)
print(round(1.5))   # 2
print(round(2.5))   # 2  (not 3)
print(round(2.675, 2))  # 2.67  (float imprecision, not 2.68)

This is intentional and reduces cumulative bias across many roundings, but it surprises people expecting 2.5 to become 3.

Useful math Module Functions

For anything beyond the basic operators, import the math module:

import math

print(math.sqrt(16))   # 4.0   (square root, always a float)
print(math.floor(3.7)) # 3     (round down to int)
print(math.ceil(3.2))  # 4     (round up to int)
print(math.pow(2, 3))  # 8.0   (returns a float)
print(2 ** 3)          # 8     (operator returns an int here)
print(abs(-5))         # 5     (built-in, no import needed)
print(math.pi)         # 3.141592653589793

Note the difference between math.pow() and **: math.pow() always returns a float, while the ** operator preserves int results when both operands are integers. For integer exponentiation, prefer **.

Wrapping Up

The arithmetic operators are quick to learn, but division behavior, signed modulo, floating-point limits, and banker's rounding are the details that separate correct code from subtle bugs. Keep these rules in mind:

  • / always returns a float; use // for integer floor division.
  • % takes the sign of the divisor, and // rounds toward negative infinity.
  • Floats are approximate — use math.isclose() or the decimal module when precision matters.
  • Guard against ZeroDivisionError whenever a divisor isn't guaranteed nonzero.

For more programming tutorials and developer tools, browse the InventiveHQ blog.

Frequently Asked Questions

Why does Python return a float when I divide two integers?

In Python 3 the single-slash operator (/) is "true division" and always returns a float, even when the result is whole: 6 / 3 is 2.0, not 2. This was a deliberate change from Python 2. If you want an integer result, use floor division (//): 6 // 3 returns 2 as an int.

What is the difference between / and // in Python?

/ is true division and always produces a float (7 / 2 is 3.5). // is floor division: it divides and rounds the result down toward negative infinity, returning an int when both operands are ints (7 // 2 is 3). For negatives the difference is sharper — -7 // 2 is -4, not -3, because it rounds down rather than toward zero.

Why is 0.1 + 0.2 not equal to 0.3 in Python?

Floats are stored in binary (IEEE 754 double precision) and most decimal fractions cannot be represented exactly, so 0.1 + 0.2 evaluates to 0.30000000000000004. This affects nearly every language, not just Python. Compare with math.isclose(0.1 + 0.2, 0.3) instead of ==, or use the decimal module when you need exact decimal math like currency.

What sign does the Python modulo operator return for negative numbers?

In Python the result of % always takes the sign of the divisor (the right-hand operand). So -7 % 2 is 1 (divisor is positive) and 7 % -2 is -1 (divisor is negative). This differs from C and Java, where the result takes the sign of the dividend.

Why does round(2.5) return 2 instead of 3 in Python?

Python's built-in round() uses round-half-to-even, also called banker's rounding. When a value is exactly halfway between two integers it rounds to the nearest even one, so round(0.5) is 0, round(2.5) is 2, and round(1.5) is 2. This reduces cumulative bias across many roundings.

What is operator precedence for Python math operators?

From highest to lowest: parentheses, then ** (exponentiation), then unary minus, then * / // % (left to right), then + - (left to right). So 1 + 2 * 3 is 7. Note ** is right-associative, meaning 2 ** 3 ** 2 evaluates as 2 ** (3 ** 2) = 512, not 64.

How do I compute a square root or cube root without importing math?

Raise the number to a fractional exponent with **: 9 ** 0.5 gives 3.0 (square root) and 27 ** (1/3) gives 3.0 (cube root). This returns a float. If you prefer, math.sqrt(9) also works but requires importing the math module.

What does divmod() do in Python?

divmod(a, b) returns a tuple of the floor-division quotient and the modulo remainder in one call: divmod(17, 5) returns (3, 2). It follows the same sign rules as // and %, so divmod(-7, 2) returns (-4, 1).

PythonProgrammingArithmeticMath ModuleBeginner
Advertisement