An Introduction to the Art of Computer Programming Using Python in the Age of Generative AI

II. Numbers and Arithmetic

Understanding how to work with numbers and perform arithmetic operations is fundamental to programming. Python provides a variety of numeric types and a rich set of operators for working with them. By mastering these core concepts, you'll be able to handle everything from simple calculations to more advanced mathematical tasks.

Integers and Floats

Python natively supports integers (whole numbers, positive or negative) and floating-point numbers (numbers with a decimal point). Integer values in Python can be arbitrarily large, limited only by your system's memory, while floats typically follow the IEEE 754 double-precision standard. You can use basic arithmetic operators like +, -, *, and / to perform operations on them.

To improve readability for large numbers, Python allows you to use underscores (_) as visual separators. Additionally, when working with very large or very small numbers—common in AI for things like "learning rates"—you can use scientific notation (e.g., 1e-4).


# Integer arithmetic
result = 5 + 7
print(f"5 + 7 = {result}")

# Large numbers with underscores (easier to read)
population = 8_000_000_000
print(f"World population: {population}")

# Scientific notation (Float)
learning_rate = 1e-4  # Equivalent to 0.0001
print(f"Learning Rate: {learning_rate}")
        

Python automatically promotes integers to floats if an operation requires floating-point arithmetic. You can also convert between types explicitly. Note that converting a float to an integer using int() truncates (cuts off) the decimal part; to round to the nearest whole number, use round().


# Converting from float to int (truncates decimals)
x = 3.9
print(f"int(3.9) is {int(x)}")

# Rounding to the nearest integer
print(f"round(3.9) is {round(x)}")

# Converting from int to float
y = 4
print(f"float(4) is {float(y)}")
        

Division and Floor Division

In Python 3, using the / operator always results in a floating-point number (even if both operands are integers). If you want to round the result down to the nearest integer, use the floor division operator //. This is particularly useful when you need integer-based results, such as calculating how many times a value fits into a range.


# Regular division
result = 8 / 3
print(f"8 / 3 = {result}")

# Floor division
result = 8 // 3
print(f"8 // 3 = {result}")
        

Note that floor division // behaves differently with negative numbers because it rounds toward negative infinity. For instance, -8 // 3 yields -3, not -2.

Modulus and Exponents

Two other operators are the % (modulus) and ** (exponent) operators. The modulus operator gives the remainder of dividing one integer by another, while the exponent operator raises a number to a given power.

Order of Operations: Just like in mathematics, Python follows precedence rules (PEMDAS). Exponents ** happen before multiplication/division * /, which happen before addition/subtraction + -. Parentheses () are used to override this order.


# Modulus
remainder = 8 % 3
print(f"Remainder of 8 % 3: {remainder}")

# Exponent
result = 2 ** 3
print(f"2 ** 3: {result}")

# Order of Operations
# Multiplication (3*2) happens first, so 5 + 6 = 11
print(f"5 + 3 * 2 = {5 + 3 * 2}")
# Parentheses force addition first, so 8 * 2 = 16
print(f"(5 + 3) * 2 = {(5 + 3) * 2}")
        

These operators also work with floats, enabling you to handle decimal results. However, when mixing floats and integers, be mindful of floating-point precision issues in certain cases.

Augmented Assignment Operators

In programming, it is very common to update a variable based on its current value (e.g., adding 1 to a score). Python provides augmented assignment operators like +=, -=, and *= to do this concisely.


score = 10
score += 5   # Same as: score = score + 5
print(f"Score after += 5: {score}")

score *= 2   # Same as: score = score * 2
print(f"Score after *= 2: {score}")
        

Complex Numbers

Python supports complex numbers natively through the letter j (or J) to denote the imaginary part. A complex number takes the form a + bj, where a is the real part and b is the imaginary part. You can perform arithmetic with them just like real numbers.


# Working with complex numbers
z = 1 + 2j
print(f"Real part: {z.real}")
print(f"Imaginary part: {z.imag}")

z2 = 2 + 3j
sum_complex = z + z2
print(f"Sum: {sum_complex}")
        
Generative AI Insight: From Scalars to Tensors
In this chapter, we handled single numbers (scalars). However, Generative AI models (like LLMs or Image Generators) work with massive grids of numbers called Tensors. While Python's built-in math is great for logic, modern AI relies on libraries like NumPy and PyTorch to perform the arithmetic operations you learned here on millions of numbers simultaneously (vectorization).

Additional Numeric Tools

For more advanced numerical computations, Python offers built-in libraries and modules:

As you progress, these tools can become vital for everything from simple data analysis to high-precision calculations and specialized domains like finance and scientific research.


import math
from decimal import Decimal
from fractions import Fraction

# Math module examples
print(f"Square root of 16: {math.sqrt(16)}")
print(f"Ceiling of 3.2: {math.ceil(3.2)}")

# Decimal helps avoid floating point errors (0.1 + 0.2 != 0.3 in floats)
print(f"Float addition: {0.1 + 0.2}")
print(f"Decimal addition: {Decimal('0.1') + Decimal('0.2')}")

# Fraction arithmetic
print(f"1/3 + 1/3 = {Fraction(1, 3) + Fraction(1, 3)}")
        
Back to Home