Python :模运算符给出不正确的结果
Python : Modulus operator giving incorrect result
我是 Python 的新手,我正在尝试将 Hill Cipher 作为一个小项目来实现。我想我已经弄清楚了逻辑并且加密部分可以正常工作,但是,在解密部分,我遇到了麻烦。特别是对于模数运算符。在下面的解密函数中,倒数第二行是造成麻烦的地方。
import numpy as np
import fractions as fr
def decrypt(matrix, words):
matrix=np.asmatrix(matrix)
length = len(matrix)
det_matrix=int(round((np.linalg.det(matrix))%26))
mult_inv=(abs(det_matrix*26)/fr.gcd(det_matrix,26))/26
matrix_inv=(((np.linalg.inv(matrix)*np.linalg.det(matrix))%26)*mult_inv)%26
words = words.lower()
arr = np.array([ord(i) - ord('a') for i in words], dtype=int)
decrypt_matrix=(np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
return decrypt_matrix
我对解密函数的输入是:
>>> matrix
[[6, 24, 1], [13, 16, 10], [20, 17, 15]]
>>> words
'poh'
并且在 det_matrix
的计算之后,mult_inv
变量的值为 25。因此计算 matrix_inv
的代码行将具有以下值,(这绝对是正确):
>>> matrix_inv
array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
数组 arr
的值为:
>>> arr
array([15, 14, 7])
现在的问题是下一行代码,在对表达式的结果执行取模之前
matrix_inv*(np.asmatrix(arr).transpose())
是:
matrix([[ 260.],
[ 574.],
[ 539.]])
现在,如果我对上述矩阵执行模数 26,我应该得到
的输出
([[0.],[2.],[19.]])
但是,下面是我执行表达式时得到的结果
>>> (np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
matrix([[ 26.],
[ 2.],
[ 19.]])
不明白为什么第一个元素计算错了(260%26是0不是26)!但是,其余两个元素已正确计算!
非常感谢任何帮助!!
P.S : 我试过 运行 2.7.11 和 3.6.1 版本的代码。两者都不起作用。
在 Python 3.5、Spyder Python 3.5.2 |Anaconda custom (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32
中工作正常
matrix_inv = np.array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
matrix_inv
Out[182]:
array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
arr = np.array([15, 14, 7])
arr
Out[184]: array([15, 14, 7])
(np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
Out[185]:
matrix([[ 0.],
[ 2.],
[ 19.]])
print(np.__version__)
1.11.1
问题是 det
是 numpy.float64
。你得到的可能是这样的:
round(259.6 % 26) # -> round(25.600000000000023) -> 26.0
这个有效:
round(259.6) % 26 # 0
在你的解密结果中你有:
dec = decrypt(matrix, words)
dec[0,0] # 25.999999999989768
dec[0,0] % 26 # 25.999999999989768
它只会显示为26.
因为我对 3x3 矩阵的模逆很感兴趣,所以我写了一些代码...也许这对您有用...
import numpy as np
from itertools import product, cycle
def gcd_xy(a, b):
'''
extended euclidean algo: return (g, x, y): g = gcd(a, b); a*x + b*y = d.
'''
q, r = divmod(a, b)
x, y, x1, y1 = 0, 1, 1, 0
while r != 0:
x1, y1, x, y = x, y, x1 - q*x, y1 - q*y
b, (q, r) = r, divmod(b, r)
return b, x, y
def mod_inv(e, n):
'''
return d == 1/e mod n or raise ValueError if e and n are not co-prime.
'''
g, d, _ = gcd_xy(e, n)
if g != 1:
msg = '{} has no inverse mod {}'.format(e, n)
raise ValueError(msg)
d %= n
return d
def mod_inv_matrix(matrix, n):
'''
modular inverse of 3x3 matrix
'''
inv = np.zeros((3, 3), dtype=int)
det = round(np.linalg.det(matrix))
det_inv = mod_inv(det, n)
matrixT = matrix.T
for (i, j), sign in zip(product(range(3), repeat=2), cycle((1, -1))):
m = np.delete(np.delete(matrixT, i, axis=0), j, axis=1)
inv[i, j] = sign * det_inv * round(np.linalg.det(m)) % n
return inv
def hill_decrypt(matrix, words):
matrix_inv = mod_inv_matrix(matrix, n=26)
words = words.lower()
arr = np.array([ord(i) - ord('a') for i in words], dtype=int)
plain = (matrix_inv @ arr) % 26
return plain
matrix = np.array([[6, 24, 1], [13, 16, 10], [20, 17, 15]], dtype=int)
words = 'poh'
dec = hill_decrypt(matrix, words)
print(dec)
对于模逆你也可以只使用 gmpy
module
import gmpy
gmpy.invert(7, 26)
我是 Python 的新手,我正在尝试将 Hill Cipher 作为一个小项目来实现。我想我已经弄清楚了逻辑并且加密部分可以正常工作,但是,在解密部分,我遇到了麻烦。特别是对于模数运算符。在下面的解密函数中,倒数第二行是造成麻烦的地方。
import numpy as np
import fractions as fr
def decrypt(matrix, words):
matrix=np.asmatrix(matrix)
length = len(matrix)
det_matrix=int(round((np.linalg.det(matrix))%26))
mult_inv=(abs(det_matrix*26)/fr.gcd(det_matrix,26))/26
matrix_inv=(((np.linalg.inv(matrix)*np.linalg.det(matrix))%26)*mult_inv)%26
words = words.lower()
arr = np.array([ord(i) - ord('a') for i in words], dtype=int)
decrypt_matrix=(np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
return decrypt_matrix
我对解密函数的输入是:
>>> matrix
[[6, 24, 1], [13, 16, 10], [20, 17, 15]]
>>> words
'poh'
并且在 det_matrix
的计算之后,mult_inv
变量的值为 25。因此计算 matrix_inv
的代码行将具有以下值,(这绝对是正确):
>>> matrix_inv
array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
数组 arr
的值为:
>>> arr
array([15, 14, 7])
现在的问题是下一行代码,在对表达式的结果执行取模之前
matrix_inv*(np.asmatrix(arr).transpose())
是:
matrix([[ 260.],
[ 574.],
[ 539.]])
现在,如果我对上述矩阵执行模数 26,我应该得到
的输出([[0.],[2.],[19.]])
但是,下面是我执行表达式时得到的结果
>>> (np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
matrix([[ 26.],
[ 2.],
[ 19.]])
不明白为什么第一个元素计算错了(260%26是0不是26)!但是,其余两个元素已正确计算!
非常感谢任何帮助!!
P.S : 我试过 运行 2.7.11 和 3.6.1 版本的代码。两者都不起作用。
在 Python 3.5、Spyder Python 3.5.2 |Anaconda custom (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32
matrix_inv = np.array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
matrix_inv
Out[182]:
array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
arr = np.array([15, 14, 7])
arr
Out[184]: array([15, 14, 7])
(np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
Out[185]:
matrix([[ 0.],
[ 2.],
[ 19.]])
print(np.__version__)
1.11.1
问题是 det
是 numpy.float64
。你得到的可能是这样的:
round(259.6 % 26) # -> round(25.600000000000023) -> 26.0
这个有效:
round(259.6) % 26 # 0
在你的解密结果中你有:
dec = decrypt(matrix, words)
dec[0,0] # 25.999999999989768
dec[0,0] % 26 # 25.999999999989768
它只会显示为26.
因为我对 3x3 矩阵的模逆很感兴趣,所以我写了一些代码...也许这对您有用...
import numpy as np
from itertools import product, cycle
def gcd_xy(a, b):
'''
extended euclidean algo: return (g, x, y): g = gcd(a, b); a*x + b*y = d.
'''
q, r = divmod(a, b)
x, y, x1, y1 = 0, 1, 1, 0
while r != 0:
x1, y1, x, y = x, y, x1 - q*x, y1 - q*y
b, (q, r) = r, divmod(b, r)
return b, x, y
def mod_inv(e, n):
'''
return d == 1/e mod n or raise ValueError if e and n are not co-prime.
'''
g, d, _ = gcd_xy(e, n)
if g != 1:
msg = '{} has no inverse mod {}'.format(e, n)
raise ValueError(msg)
d %= n
return d
def mod_inv_matrix(matrix, n):
'''
modular inverse of 3x3 matrix
'''
inv = np.zeros((3, 3), dtype=int)
det = round(np.linalg.det(matrix))
det_inv = mod_inv(det, n)
matrixT = matrix.T
for (i, j), sign in zip(product(range(3), repeat=2), cycle((1, -1))):
m = np.delete(np.delete(matrixT, i, axis=0), j, axis=1)
inv[i, j] = sign * det_inv * round(np.linalg.det(m)) % n
return inv
def hill_decrypt(matrix, words):
matrix_inv = mod_inv_matrix(matrix, n=26)
words = words.lower()
arr = np.array([ord(i) - ord('a') for i in words], dtype=int)
plain = (matrix_inv @ arr) % 26
return plain
matrix = np.array([[6, 24, 1], [13, 16, 10], [20, 17, 15]], dtype=int)
words = 'poh'
dec = hill_decrypt(matrix, words)
print(dec)
对于模逆你也可以只使用 gmpy
module
import gmpy
gmpy.invert(7, 26)