Skip to content

Python Numbers & Arithmetic

Python has two primary numeric types: integers (int) for whole numbers and floats (float) for numbers with a decimal point. A third type, complex (for example 3 + 4j), exists for engineering and scientific work but is rarely needed day to day.

TaskToolExample
Basic math+, -, *, /7 / 2 gives 3.5
Whole-number division//7 // 2 gives 3
Remainder%7 % 2 gives 1
Power**2 ** 3 gives 8
Update a variable+=, -=, *=, …count += 1
Convertint(), float()int('45') gives 45
Roundround(n, digits)round(4.253, 1) gives 4.3
Quotient and remainder togetherdivmod(a, b)divmod(17, 5) gives (3, 2)
Advanced mathimport mathmath.sqrt(16) gives 4.0

  • Integer (int): whole numbers, positive or negative (56, -4, 0).
  • Float (float): numbers with a decimal point (3.14, -12.0, 0.0).
numeric_types.py
population = 8_100_000_000 # Underscores improve readability
temperature = -4.5
scientific = 1.5e3 # 1500.0, scientific notation always gives a float
print(2 ** 100) # 1267650600228229401496703205376, ints never overflow
print(0b101, 0o17, 0xff) # 5 15 255, binary, octal, and hex literals

If you mix an int and a float in an operation, Python converts the result to a float. Standard division (/) always returns a float, even when dividing two integers evenly.

ExpressionResultType
5 + 38int
5 + 3.08.0float
10 / 25.0float
10 // 25int
2 ** -10.5float

OperatorOperationExampleResult
+Addition7 + 29
-Subtraction7 - 25
*Multiplication7 * 214
/True division (always a float)7 / 23.5
//Floor division7 // 23
%Modulo (remainder)7 % 21
**Exponentiation7 ** 249
-xNegation-(7)-7

// divides and rounds down to the nearest whole number. % returns what is left over. Together they satisfy the identity a == (a // b) * b + a % b.

floor_and_modulo.py
print(17 // 5) # 3, how many times 5 fits into 17
print(17 % 5) # 2, what remains
print(divmod(17, 5)) # (3, 2), both at once
print(7.5 // 2) # 3.0, with floats the result is still a float
print(-7 // 2) # -4, rounds down toward negative infinity, not toward zero
print(-7 % 3) # 2, the result takes the sign of the right-hand number

Common uses for modulo:

modulo_uses.py
number = 14
print(number % 2 == 0) # True, even number check
print(number % 7 == 0) # True, divisibility check
print((23 + 5) % 24) # 4, wrap-around (5 hours after 23:00 is 04:00)
powers_and_roots.py
print(2 ** 3) # 8
print(2 ** -1) # 0.5
print(16 ** 0.5) # 4.0, a fractional exponent gives a root

Dividing by zero with /, //, or % raises a ZeroDivisionError. Guard against it when the divisor comes from user input or calculations.

zero_division.py
divisor = 0
if divisor != 0:
print(10 / divisor)
else:
print('Cannot divide by zero') # Runs

Python follows the standard order of operations. Operators on the same level are evaluated left to right, with one exception: ** is evaluated right to left.

PriorityOperators
1 (highest)Parentheses ()
2**
3Unary -x, +x
4*, /, //, %
5 (lowest)+, -
precedence.py
print(2 + 3 * 4) # 14, multiplication first
print((2 + 3) * 4) # 20, parentheses override
print(2 ** 3 ** 2) # 512, evaluated as 2 ** (3 ** 2)
print(-2 ** 2) # -4, evaluated as -(2 ** 2)
print((-2) ** 2) # 4
print(10 - 2 - 3) # 5, left to right

Augmented assignment is shorthand for updating a variable: variable operator= value means variable = variable operator value.

OperatorEquivalent toExampleResult
+=x = x + ncount = 14; count += 317
-=x = x - ncount = 14; count -= 311
*=x = x * ncount = 14; count *= 228
/=x = x / nprice = 100; price /= 425.0 (always a float)
//=x = x // ncount = 14; count //= 43
%=x = x % nbits = 35; bits %= 21
**=x = x ** npower = 2; power **= 38
augmented_assignment.py
total = 0
total += 10 # 10
total += 5 # 15
total *= 2 # 30
total -= 4 # 26
print(total) # 26

FunctionPurposeExampleResult
int(x)Convert to an integer, truncating decimals toward zeroint(12.925)12
int(x)Parse a numeric stringint('45')45
float(x)Convert to a floatfloat(56)56.0
float(x)Parse a numeric stringfloat('7.8')7.8
round(x)Round to the nearest integerround(4.798)5
round(x, n)Round to n decimal placesround(4.253, 1)4.3
abs(x)Absolute valueabs(-15)15
pow(b, e)Same as b ** epow(2, 3)8
pow(b, e, m)Efficient (b ** e) % mpow(2, 3, 5)3
divmod(a, b)Quotient and remainder as a tupledivmod(17, 5)(3, 2)
min() / max()Smallest or largest valuemax(4, 9, 2)9
sum(items)Total of an iterablesum([1, 2, 3])6
function_details.py
# int() truncates toward zero. It does not round.
print(int(3.9)) # 3
print(int(-3.9)) # -3
# int() cannot parse a decimal string directly
print(int('3.5')) # ValueError
print(int(float('3.5'))) # 3
# round() uses "banker's rounding": halves go to the nearest even number
print(round(2.5)) # 2
print(round(3.5)) # 4
# A negative digits value rounds to tens, hundreds, and so on
print(round(1234, -2)) # 1200
# Parsing numbers in other bases
print(int('ff', 16)) # 255
print(int('101', 2)) # 5

Modules are covered in more detail in the Modules & Packages section.

For roots, rounding up or down, and constants, import the standard math module.

math_module.py
import math
print(math.sqrt(16)) # 4.0
print(math.floor(3.7)) # 3, rounds down
print(math.ceil(3.2)) # 4, rounds up
print(math.floor(-3.5)) # -4
print(math.ceil(-3.5)) # -3
print(math.trunc(-3.9)) # -3, drops the decimals
print(math.pi) # 3.141592653589793
print(math.isclose(0.1 + 0.2, 0.3)) # True

Computers store floats as binary approximations, and some decimal fractions cannot be represented exactly.

float_precision.py
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
print(round(2.675, 2)) # 2.67, not 2.68, because 2.675 is stored as 2.67499999...

This is not a Python bug. It is how floating-point numbers work in every mainstream language. Choose the fix that fits your situation:

Use math.isclose() instead of ==.

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

  1. Clean incoming values. Data from input(), files, and APIs arrives as strings. Convert it with int() or float(), and handle ValueError.

  2. Choose the right operator. Use / for exact quotients, // for whole-number results, and % for remainders.

  3. Update in place. Use +=, *=, and friends to avoid repeating variable names.

  4. Round at the end. Keep full precision during calculations and round only for display.

parse_and_calculate.py
raw_quantity = '45.5'
try:
quantity = float(raw_quantity)
except ValueError:
print(f'{raw_quantity!r} is not a valid number')
else:
print(f'Half of {quantity} is {quantity / 2}') # Half of 45.5 is 22.75
worked_examples.py
# Average of a list
scores = [88, 92, 79]
average = sum(scores) / len(scores)
print(f'Average: {average:.2f}') # Average: 86.33
# Applying a discount
price = 80
discounted = round(price * 0.85, 2)
print(discounted) # 68.0
# Converting seconds to hours, minutes, seconds
total_seconds = 3725
hours, remainder = divmod(total_seconds, 3600)
minutes, seconds = divmod(remainder, 60)
print(f'{hours}h {minutes}m {seconds}s') # 1h 2m 5s

MistakeProblemFix
0.1 + 0.2 == 0.3Floating-point approximationmath.isclose(a, b)
int(3.9) expecting 4Truncates, does not roundround(3.9)
int('3.5')ValueErrorint(float('3.5'))
-2 ** 2 expecting 4** binds tighter than unary minus(-2) ** 2
10 / 2 expecting 5/ always returns a float (5.0)10 // 2
-7 // 2 expecting -3Floors toward negative infinityint(-7 / 2) to truncate
'Age: ' + 26TypeError, cannot add str and intf'Age: {26}'
x / 0ZeroDivisionErrorCheck the divisor first
round(2.5) expecting 3Banker’s rounding gives 2Use Decimal with an explicit rounding mode when exact halves matter
Using floats for moneyRounding driftDecimal('19.99')
  1. Use // and % when you need whole-number results, and / when you need exact quotients.
  2. Add parentheses to any expression where precedence is not obvious.
  3. Never compare floats with ==. Use math.isclose().
  4. Use Decimal, built from strings, for money and other exact decimal values.
  5. Keep full precision while calculating, and round only for display.
  6. Wrap conversions of untrusted input in try / except ValueError.
  7. Guard divisions where the divisor might be zero.
  8. Use augmented assignment (+=, *=) for clearer, shorter updates.