Python Program to Print Powers from 1 to 5 of Numbers from 1 to 20

Python Program to Print Powers from 1 to 5 of Numbers from 1 to 20

Computing powers of numbers is a fundamental programming exercise that demonstrates loops, formatting, and mathematical operations in Python. This article explores multiple approaches to printing the powers (x^1 through x^5) for numbers 1 through 20, ranging from basic loops to NumPy-based vectorized solutions. Each approach teaches different Python concepts while producing the same tabular output.

Basic Nested Loop Approach

The simplest solution uses two nested for loops: an outer loop iterating numbers 1 through 20, and an inner loop computing powers 1 through 5. Python’s exponentiation operator (**) computes powers efficiently. Using formatted string literals (f-strings) with width specifiers aligns the output into readable columns. The print() function’s end parameter controls spacing between columns, and an empty print() at the end of each row creates the line break.

# Print powers 1-5 for numbers 1-20
for num in range(1, 21):
    for exp in range(1, 6):
        result = num ** exp
        print(f"{result:>10}", end=" ")
    print()  # New line after each row

Using List Comprehension for Compact Code

List comprehensions generate each row as a list of power values, then join them into a formatted string. This approach is more Pythonic and separates data generation from presentation. The join() method with formatted strings avoids repeated print() calls, which is slightly more performant for large outputs. The pattern also teaches an important skill: separating computation logic from output formatting, making the code easier to modify or repurpose.

for num in range(1, 21):
    row = [str(num ** exp).rjust(10) for exp in range(1, 6)]
    print(" ".join(row))

NumPy Vectorized Solution

For maximum performance (especially with larger ranges), NumPy’s broadcasting computes all powers at once. The outer product of two arrays—numbers and exponents—creates a 2D matrix where element (i,j) = numbers[i]^exponents[j]. NumPy’s vectorized operations execute in C, making this approach orders of magnitude faster for large ranges. This introduces the concept of broadcasting, one of NumPy’s most powerful features for eliminating explicit Python loops.

import numpy as np

numbers = np.arange(1, 21).reshape(-1, 1)  # Column vector (20,1)
exponents = np.arange(1, 6)                # Row vector    (1,5)
powers = numbers ** exponents              # Broadcast →  (20,5)

# Format and print
for row in powers:
    print(" ".join(f"{val:>10}" for val in row))

Understanding the Output Pattern

The output is a 20×5 matrix where each row shows increasing powers of a number: row 1 is 1^1=1, 1^2=1, 1^3=1, 1^4=1, 1^5=1; row 10 is 10, 100, 1000, 10000, 100000; and row 20 grows exponentially to 20, 400, 8000, 160000, 3200000. This exercise teaches iteration, exponentiation, formatted output, and the relationship between numbers and their powers. The same pattern extends to other mathematical functions like factorials, Fibonacci sequences, or multiplication tables, reinforcing the general concept of nested iteration over parameter ranges.

Extending the Program with User Input

Making the program interactive with user-specified ranges makes it more flexible. Using input() and sys.argv, users can set the maximum number, the exponent range, and output format (table vs CSV). Adding file output with redirect (python powers.py > output.txt) or programmatic CSV generation makes the data usable in spreadsheet applications. Error handling for non-numeric input and unreasonably large ranges (where numbers overflow Python’s arbitrary-precision integers) prevents crashes. Python’s integers have arbitrary precision, so 20^5 = 3.2 million prints correctly, but 100^100 has 201 digits and prints without overflow—something many languages cannot do. This exercise also demonstrates the computational cost: computing powers for numbers up to 10,000 with exponents to 10 generates 100,000 calculations, showcasing the difference between O(n) and O(n×m) complexity.

import sys
max_num = int(sys.argv[1]) if len(sys.argv) > 1 else 20
max_exp = int(sys.argv[2]) if len(sys.argv) > 2 else 5
import csv, io
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(['number'] + [f'^{e}' for e in range(1, max_exp+1)])
for n in range(1, max_num+1):
    writer.writerow([n] + [n**e for e in range(1, max_exp+1)])
print(output.getvalue())

Mathematical Patterns in Power Sequences

Computing power sequences reveals interesting mathematical patterns. Numbers ending in 0 always end in 0 for any exponent. Numbers ending in 1, 5, or 6 always end in the same digit (1^5 ends in 1, 6^3 ends in 6). Numbers ending in 2 cycle through 2, 4, 8, 6. Numbers ending in 3 cycle through 3, 9, 7, 1. These patterns come from modular arithmetic: the last digit of a power depends only on the last digit of the base, and the cycle length divides 4 (by Euler’s theorem). The sequence 1^n = 1 for all n, while 2^10 = 1024 grows past 1000. This exercise demonstrates exponential growth, modulo arithmetic, and the difference between polynomial and exponential functions—concepts foundational to algorithm analysis and computational complexity theory.