在我的 Hill Cipher 代码中(在解密过程中),将float转换为int的结果不同。
代码:https://github.com/krshrimali/Hill-Cipher/blob/master/hill_cipher.py
问题:https://github.com/krshrimali/Hill-Cipher/issues/1
代码:
# create empty plain text string
plain_text = ""
# result is a matrix [[260. 574. 439.]]
# addition of 65 because inputs are uppercase letters
for i in range(dimensions):
plain_text += chr(int(result[0][i]) % 26 + 65)
输出:ABS
(密文-加密文本-是POH)
结果矩阵 :(将逆矩阵与密码密钥矩阵相乘)
[[ 260. 574. 539.]]
转换为int后:
[260, 573, 538]
任何人都可以解释为什么会发生这种情况并对此进行修复吗?谢谢。
答案 0 :(得分:1)
问题是您使用的是int
,它会截断为零。
具有float
值的数学运算本质上是不精确的。如果您不明白为什么,则经典解释在What Every Computer Scientist Should Know About Floating-Point Numbers中。但是简短的版本是每次转换和每个中间计算都将四舍五入到与实际数字最接近的52位小数。这可能意味着,如果使用实数执行,则将产生恰好为574的计算,实际上使用float
执行时,所产生的数字比574略多或略少。并且如果最后得到的数字比574小一点,并用int
将其截断为零,则会得到573
。
在这种情况下,您要使用的是round
,它会四舍五入到最接近的整数。只要您可以确定累积的误差永远不会大于0.5,就可以做到您想要的。而且,只要您没有选择可笑的巨大键值(这将是毫无意义的,因为那样就不会获得更多的安全性),您就可以确定。
但是,这里有两件事值得考虑。
摘自Wikipedia上的Hill cipher文章的简要扫描:它旨在通过快速的铅笔和纸操作来执行。首先,您不需要逆矩阵,只需一个逆模数为26的矩阵,该矩阵就更容易计算,并且意味着您所用的数字较小,因此不太可能出现此问题。这意味着您可以用整数进行所有数学运算,因此首先不会出现问题:使用dtype=int
将矩阵创建为数组,并且不会出现舍入问题。而且,作为奖励,如果您做选择非常大的键值,则会得到一个错误而不是错误的结果。 (如果要允许这样的值,则希望将Python大小不受限制的int
值存储在dtype=object
数组中。但是,如果不需要它,那只会使事情变得越来越慢。复杂。)