Skip to content

SEMI-ADVANCED POW() EXAMPLES

Python
#!/usr/bin/env python3
"""
SEMI-ADVANCED POW() EXAMPLES
Modular arithmetic, optimization, and advanced applications
"""

import time

print("=" * 60)
print("SEMI-ADVANCED POW() - Modular Arithmetic & Optimization")
print("=" * 60)

# Example 1: Three-argument form (modular exponentiation)
print("\n1. Modular Exponentiation: pow(base, exp, mod)")
print("-" * 40)
print("Calculate (base^exp) % mod efficiently:\n")

base, exp, mod = 7, 100, 13
result_modular = pow(base, exp, mod)
print(f"pow({base}, {exp}, {mod}) = {result_modular}")
print(f"This computes ({base}^{exp}) mod {mod} efficiently")

print("\nComparison with manual modulo:")
result_manual = pow(base, exp) % mod
print(f"pow({base}, {exp}) % {mod} = {result_manual}")
print(f"Both methods give same result: {result_modular == result_manual}")

# Example 2: Why modular pow is more efficient
print("\n2. Efficiency: Modular vs Manual (Large Numbers)")
print("-" * 40)

base, exp, mod = 12345, 67890, 10007

# Using three-argument pow (efficient)
start = time.time()
result_efficient = pow(base, exp, mod)
time_efficient = time.time() - start

# Using manual method (creates huge intermediate number)
start = time.time()
result_manual = pow(base, exp) % mod
time_manual = time.time() - start

print(f"Base: {base}, Exponent: {exp}, Modulo: {mod}\n")
print(f"Three-argument pow(): {result_efficient}")
print(f"  Time: {time_efficient:.6f} seconds")
print(f"\nManual (pow then mod): {result_manual}")
print(f"  Time: {time_manual:.6f} seconds")
print(f"\nSpeedup: {time_manual / time_efficient:.2f}x faster" if time_efficient > 0 else "")

# Example 3: Checking last digits (modulo 10, 100, 1000)
print("\n3. Finding Last Digits of Large Powers")
print("-" * 40)

base = 7
exp = 1000

last_1_digit = pow(base, exp, 10)
last_2_digits = pow(base, exp, 100)
last_3_digits = pow(base, exp, 1000)

print(f"Calculating {base}^{exp}:")
print(f"  Last 1 digit: {last_1_digit}")
print(f"  Last 2 digits: {last_2_digits:02d}")
print(f"  Last 3 digits: {last_3_digits:03d}")

# Example 4: Modular patterns (cyclic behavior)
print("\n4. Modular Patterns: Powers Cycle")
print("-" * 40)

base = 3
mod = 7

print(f"Pattern of {base}^n mod {mod}:")
print("n  | 3^n mod 7")
print("---|----------")

for n in range(1, 13):
    result = pow(base, n, mod)
    print(f"{n:2d} | {result}")

print("\nNotice the pattern repeats!")

# Example 5: Cryptography basics - modular inverse
print("\n5. Modular Inverse Using pow()")
print("-" * 40)
print("For prime modulus p, modular inverse of a is: pow(a, p-2, p)\n")

a = 38
p = 97  # Prime number

# Calculate modular inverse
inv = pow(a, p - 2, p)
# Verify: (a * inv) mod p should equal 1
verification = (a * inv) % p

print(f"Number: {a}")
print(f"Prime modulus: {p}")
print(f"Modular inverse: {inv}")
print(f"Verification: ({a} * {inv}) mod {p} = {verification}")
print(f"Is inverse correct? {verification == 1}")

# Example 6: RSA-like calculation (simplified)
print("\n6. RSA-Style Encryption/Decryption (Simplified)")
print("-" * 40)

message = 42
e = 17  # Public exponent
d = 2753  # Private exponent (pre-calculated)
n = 3233  # Modulus (61 * 53)

# Encryption: c = m^e mod n
ciphertext = pow(message, e, n)
print(f"Original message: {message}")
print(f"Public key (e, n): ({e}, {n})")
print(f"Encrypted: {ciphertext}")

# Decryption: m = c^d mod n
decrypted = pow(ciphertext, d, n)
print(f"\nPrivate key (d): {d}")
print(f"Decrypted: {decrypted}")
print(f"Decryption successful? {decrypted == message}")

# Example 7: Fermat's Little Theorem verification
print("\n7. Fermat's Little Theorem: a^(p-1) ≡ 1 (mod p)")
print("-" * 40)
print("For prime p and a not divisible by p:\n")

primes = [5, 7, 11, 13, 17]
a = 3

print(f"Testing with a = {a}:")
print("Prime p | a^(p-1) mod p")
print("--------|---------------")

for p in primes:
    result = pow(a, p - 1, p)
    print(f"   {p:2d}   |      {result}")

print("\nAll results are 1, confirming the theorem!")

# Example 8: Finding remainders for large calculations
print("\n8. Calendar Calculations: Day of Week")
print("-" * 40)
# If today is day 0, what day is it after 10^100 days?

days_in_week = 7
huge_days = pow(10, 100)  # Can't compute this directly

# But we can find remainder efficiently
day_of_week = pow(10, 100, days_in_week)

weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"]

print(f"If today is {weekdays[0]},")
print(f"what day is it after 10^100 days?")
print(f"\nRemainder when dividing by 7: {day_of_week}")
print(f"Answer: {weekdays[day_of_week]}")

# Example 9: Chinese Remainder Theorem application
print("\n9. Solving System with Modular Arithmetic")
print("-" * 40)
# Find x such that x ≡ 2 (mod 5) and x ≡ 3 (mod 7)

# Testing possible values
print("Finding x where x ≡ 2 (mod 5) and x ≡ 3 (mod 7):\n")

solutions = []
for x in range(0, 100):
    if pow(x, 1, 5) == 2 and pow(x, 1, 7) == 3:  # x mod 5 == 2 and x mod 7 == 3
        solutions.append(x)
        if len(solutions) <= 5:
            print(f"  x = {x}")

print(f"\nPattern: solutions differ by {5 * 7} = 35")
print(f"General solution: x = {solutions[0]} + 35k (k = 0, 1, 2, ...)")

# Example 10: Performance with very large numbers
print("\n10. Handling Astronomical Numbers")
print("-" * 40)

# Calculate something that would overflow without modular arithmetic
base = 123456789
exp = 987654321
mod = 1000000007  # Large prime often used in competitive programming

print(f"Computing {base}^{exp} mod {mod}")
print("(Direct computation would create number with ~80 million digits!)\n")

start = time.time()
result = pow(base, exp, mod)
elapsed = time.time() - start

print(f"Result: {result}")
print(f"Computed in: {elapsed:.6f} seconds")
print(f"\nWithout modular form, this would:")
print(f"  - Require gigabytes of memory")
print(f"  - Take hours or days to compute")

# Example 11: Digital signatures verification
print("\n11. Digital Signature Verification Concept")
print("-" * 40)

# Simplified signature scheme
message_hash = 1234
private_key = 107
public_key = 29
modulus = 187

# Sign: signature = hash^private_key mod n
signature = pow(message_hash, private_key, modulus)
print(f"Message hash: {message_hash}")
print(f"Signature: {signature}")

# Verify: hash should equal signature^public_key mod n
verified_hash = pow(signature, public_key, modulus)
print(f"\nVerification:")
print(f"  signature^public_key mod n = {verified_hash}")
print(f"  Original hash = {message_hash}")
print(f"  Valid signature? {verified_hash == message_hash}")

# Example 12: Optimization comparison
print("\n12. Memory Comparison: Huge vs Modular")
print("-" * 40)

base, exp = 999, 10000

# Show size difference
huge_number = pow(base, exp)
modular_result = pow(base, exp, 1000000)

huge_digits = len(str(huge_number))
huge_bytes = huge_number.bit_length() // 8

print(f"Computing {base}^{exp}:")
print(f"\nDirect computation:")
print(f"  Number of digits: {huge_digits:,}")
print(f"  Approximate bytes: {huge_bytes:,}")
print(f"  First 50 digits: {str(huge_number)[:50]}...")
print(f"\nModular computation (mod 1000000):")
print(f"  Result: {modular_result}")
print(f"  Memory: just a few bytes")

print("\n" + "=" * 60)
print("Key Concepts:")
print("  - pow(base, exp, mod) is MUCH faster than pow(base, exp) % mod")
print("  - Essential for cryptography (RSA, signatures)")
print("  - Enables working with astronomical numbers")
print("  - Modular inverse: pow(a, p-2, p) when p is prime")
print("  - Pattern detection through modular cycles")
print("=" * 60)