alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
# Multiplication cipher
def mult_cipher(plaintext, key):
"""Convert each char c to number n using alpha.
Then n->n*key mod 26. Convert back to char"""
ciphertext = []
for i in range(len(plaintext)):
c = plaintext[i]
numc = alpha.find(c)
multnumc = (numc*key) % 26 # only significant change vs shift_cipher
codedc = alpha[multnumc]
ciphertext.append(codedc)
return ciphertext
mult_cipher("HELLO",3)
"".join(mult_cipher("ABCDEFGHIJKLMNOPQRSTUVWXYZ",3))
# To decipher, use mult_cipher(ciphertext, 9)
# we use 9 as the decryption key since 3*9 % 26 = 1
mult_cipher(['V', 'M', 'H', 'H', 'Q'], 9)
mult_cipher("HELLO",2)
"".join(mult_cipher("ABCDEFGHIJKLMNOPQRSTUVWXYZ",2))
mult_cipher("A",2)
mult_cipher("N",2)
# since above are the same, can't decrypt "A"
# so 2 is not a good encryption key to use, the problem is that
# 2,26 share a common factor
# Want to have a way of deciding whether a given key can be inverted,
# need to compute greatest common divisor (gcd)
# Digression: recursion
# factorial function using loop (no recursion)
def fact_loop(n):
"""Return n*(n-1)*...*1 """
run_prod = 1
for i in range(1,n+1):
run_prod = run_prod*i
return run_prod
fact_loop(5)
# Factorial function using recursion
def fact(n):
#print(n)
if n==1:
return 1 # base case
else:
return n*fact(n-1) # calls same function: recursive call
fact(100)
# CHALLENGE: compute nth term of Fibonacci sequence using recursion
# a0 = 1, a1 = 1, a2 = 2, a3 = 3, a4 = 5, a5 = 8,
# a_n =a_{n-1} + a_{n-2} for n>=1
def fib(n):
"""Returns nth fibonacci number an, uses recursion."""
if n==0 or n==1:
return 1
return fib(n-1)+fib(n-2)
# for testing
[fib(n) for n in range(10)]
fib(20)
# this fib function is slower than the fib function from a previous class
# Reason: there is a slot of redunancy
# (for instance, computes fib(n-2) multiple times)