【问题标题】:Python : Modulus operator giving incorrect resultPython:模运算符给出不正确的结果
【发布时间】:2017-11-18 21:00:45
【问题描述】:

我对 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 版本上运行代码。两者都不起作用。

【问题讨论】:

  • 到目前为止我唯一尝试过的就是检查(matrix @ matrix_inv)%26 = 1。这不是……

标签: python arrays matrix modulus


【解决方案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

【讨论】:

  • 我正在使用2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:32:19) [MSC v.1500 32 bit (Intel)]我会升级版本再试一次。谢谢!
  • 也不适用于 3.6.1。 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
  • 听起来像是可能的错误 - 必须让比我了解更多的人感兴趣才能解决问题
【解决方案2】:

问题是detnumpy.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)

【讨论】:

  • 谢谢!我会花一些时间来消化这个。但是,当我提供 4x4 输入但不适用于这个 3x3 输入时,相同的逻辑(我写的那个)真的很奇怪!
  • 你不认为这只是偶然吗? (是的:我的回答没有为一般的n*n 矩阵提供解决方案)。
  • 我想是的。我想我会花更多时间调查(并更好地理解)程序的这种奇怪行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多