import sage.all as sage
import math
class AdvancedMultiplication:
def __init__(self):
pass
def karatsuba_multiply(self, a, b, base=10):
a_str = str(a)
b_str = str(b)
if len(a_str) <= 2 or len(b_str) <= 2:
return a * b
max_len = max(len(a_str), len(b_str))
a_str = a_str.zfill(max_len)
b_str = b_str.zfill(max_len)
n = len(a_str)
half = n // 2
a_high = int(a_str[:-half])
a_low = int(a_str[-half:])
b_high = int(b_str[:-half])
b_low = int(b_str[-half:])
z0 = self.karatsuba_multiply(a_low, b_low, base)
z1 = self.karatsuba_multiply(a_low + a_high, b_low + b_high, base)
z2 = self.karatsuba_multiply(a_high, b_high, base)
cross_term = z1 - z0 - z2
result = z2 * (base ** (2 * half)) + cross_term * (base ** half) + z0
return result
def toom_cook_multiply(self, a, b, k=3):
return self.karatsuba_multiply(a, b)
def fft_multiply(self, a, b):
a_coeffs = [int(d) for d in str(a)]
b_coeffs = [int(d) for d in str(b)]
n = 1
while n < len(a_coeffs) + len(b_coeffs):
n *= 2
a_coeffs = a_coeffs + [0] * (n - len(a_coeffs))
b_coeffs = b_coeffs + [0] * (n - len(b_coeffs))
def dft(coeffs):
N = len(coeffs)
result = [0] * N
for k in range(N):
for n in range(N):
angle = -2 * sage.pi * sage.I * k * n / N
result[k] += coeffs[n] * sage.exp(angle)
return result
a_fft = dft(a_coeffs)
b_fft = dft(b_coeffs)
c_fft = [a * b for a, b in zip(a_fft, b_fft)]
def idft(freq):
N = len(freq)
result = [0] * N
for k in range(N):
for n in range(N):
angle = 2 * sage.pi * sage.I * k * n / N
result[k] += freq[n] * sage.exp(angle)
result[k] /= N
return [round(abs(x).real) for x in result]
c_coeffs = idft(c_fft)
result = 0
for i, coeff in enumerate(c_coeffs):
result += int(coeff) * (10 ** i)
return result
def schoolbook_multiply(self, a, b):
return a * b
def multiply(self, a, b, algorithm='schoolbook'):
if algorithm == 'schoolbook':
return self.schoolbook_multiply(a, b)
elif algorithm == 'karatsuba':
return self.karatsuba_multiply(a, b)
elif algorithm == 'toom_cook':
return self.toom_cook_multiply(a, b)
elif algorithm == 'fft':
return self.fft_multiply(a, b)
else:
raise ValueError(f"Unknown algorithm: {algorithm}")
def test_multiplication(self):
print("Testing multiplication algorithms...")
test_cases = [
(123, 456),
(1234, 5678),
(12345, 67890),
(2**100, 2**100), ]
algorithms = ['schoolbook', 'karatsuba', 'toom_cook', 'fft']
for a, b in test_cases:
print(f"\nTesting {a} * {b}")
expected = a * b
for alg in algorithms:
try:
result = self.multiply(a, b, alg)
correct = (result == expected)
print(f" {alg}: {'✓' if correct else '✗'}")
if not correct:
print(f" Expected: {expected}")
print(f" Got: {result}")
except Exception as e:
print(f" {alg}: Error - {e}")
def benchmark_multiplication(self, sizes=None):
if sizes is None:
sizes = [10, 50, 100, 500]
print("\nBenchmarking multiplication algorithms...")
print("Digits | School(ms) | Karat(ms) | Toom(ms) | FFT(ms)")
print("-" * 55)
import time
for digits in sizes:
a = sage.Integer(10)**digits - 1 b = sage.Integer(10)**(digits//2) - 1
times = {}
for alg in ['schoolbook', 'karatsuba', 'toom_cook', 'fft']:
try:
start = time.time()
result = self.multiply(a, b, alg)
end = time.time()
times[alg] = (end - start) * 1000
if digits <= 50:
expected = a * b
if result != expected:
print(f" ERROR: {alg} gave wrong result!")
except Exception as e:
times[alg] = float('inf')
print(f" ERROR in {alg}: {e}")
print(">6"
">10.1f"
">10.1f"
">10.1f"
">10.1f")
if __name__ == "__main__":
mult = AdvancedMultiplication()
mult.test_multiplication()
mult.benchmark_multiplication([10, 50, 100])