Python 3.2与3.3中数值模拟结果不同

4
这可能是一个奇怪的问题,但是请听我说:
我有一个数值模拟程序。它不是特别长的程序,但是解释起来有点长。我运行这个模拟程序一千次,并计算平均结果和方差,方差非常小,大约为10^(-30)。
然而,我注意到当我在Python 3.3中运行程序时会出现奇怪的情况。在Python 2.7和Python 3.2中,每次都得到相同的答案。相同的平均值,相同的微小方差。
但是当我在Python 3.3中运行时,每次都会得到不同的答案。也就是说,不同的平均值和不同(但仍然很小)的方差。这非常奇怪,因为概率定律表明,如果方差实际上很小,那么这种情况是不可能发生的。所以我想知道,自从3.2以来,在3.3解释器中发生了什么变化,导致我的模拟程序出现问题?
以下是我想到的一些事情:
  • 我可能在Python版本的32位/64位之间存在奇怪的差异,但是我检查过了,它们都在64位上运行。
  • 我可能在浮点/整数转换中出现了一些错误,但是在Python 3.2中会处理这个问题,因为他们使除法在适当时返回浮点数,所以3.2和3.3的结果应该是相同的。
  • 我的模拟程序被表示为生成器,因此可能在3.3中与生成器有关的某些内容发生了变化,但我无法确定具体变化。
  • 有一些我不知道的数值浮点表示方式的变化。
  • 有一些函数的底层变化导致了算法的初始条件受到影响。例如,在我的代码中,我使用“list(table.keys())”对最初是字典的数据列进行排序,从3.2到3.3,list决定如何对字典键进行排序可能发生了变化。但如果是这种情况,那么代码每次都应该执行相同的操作,但它没有(故意使列表的排序随机似乎非常奇怪!)。
有人能指出从3.2到3.3发生了什么变化,可能导致我的问题吗?
2个回答

9
你最后一个要点很可能是原因。在python3.3,哈希随机化默认启用以解决安全问题。基本上,你现在永远不知道你的字符串将如何哈希(这确定了它们在字典中的顺序)。
这里有一个演示:
d = {"a": 1, "b": 2, "c": 3}
print(d)

在我的电脑上,使用Python3.4,这会导致3个不同的排序结果:
$ python3.4 test.py
{'a': 1, 'c': 3, 'b': 2}
$ python3.4 test.py
{'c': 3, 'b': 2, 'a': 1}
$ python3.4 test.py
{'b': 2, 'c': 3, 'a': 1}

在哈希随机化之前,如果您知道一个字符串的哈希值,那么具有足够应用程序知识的恶意攻击者可能会向其提供数据,以导致字典查找运行的时间为O(n),而不是通常的字典查找的O(1)。这可能会导致某些应用程序的严重性能下降。
您可以按照此处文档中所述禁用哈希随机化。在某些情况下,他们还引入了一个-R标志到Python中,该标志基于“选择性加入”的基础上启用哈希随机化。该选项至少适用于Python3.2,因此您可以使用它来测试我们的假设。

更好的是:这向我展示了我的实验对初始条件的敏感程度。因此,我应该随机排列列的顺序,以获得更好的预期结果图像。 - JeremyKun

3

设置环境变量

PYTHONHASHSEED

尝试将其设置为0,看看是否有帮助(这样可以避免您费力查找mgilson提供的链接;-))。

但请注意,从未定义过字典遍历的顺序。要获得真正可重复的结果,您需要强制自己的顺序。例如,使用以下方式是否会存在任何真正的问题:

sorted(table)

你是否考虑使用替代方案?这样你就不必再担心32位和64位、哈希随机化、未来的bugfixes改变顺序等问题。


1
但是链接呈现出非常漂亮的蓝色(如果你点击了它,就是紫色...):)。对于排序键以获得真正可重复的结果的观点很好。 - mgilson
过去情况是任意的,但是确定性的。我甚至在那个年代测试过它,因为我很好奇。 - JeremyKun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接