Python浮点数确定性问题

7
下面的代码(用于计算余弦相似度),在我的电脑上反复运行时,会输出1.0、0.9999999999999998或1.0000000000000002。当我去掉normalize函数时,它只会返回1.0。我以为浮点运算应该是确定性的。如果同样的操作在同一台计算机上应用于相同的数据,那么这在我的程序中会引起什么问题?也许与normalize函数被调用的堆栈位置有关吗?我该如何避免这种情况发生?
#! /usr/bin/env python3

import math

def normalize(vector):
    sum = 0
    for key in vector.keys():
        sum += vector[key]**2
    sum = math.sqrt(sum)
    for key in vector.keys():
        vector[key] = vector[key]/sum
    return vector

dict1 = normalize({"a":3, "b":4, "c":42})
dict2 = dict1

n_grams = list(list(dict1.keys()) + list(dict2.keys()))
numerator = 0
denom1 = 0
denom2 = 0

for n_gram in n_grams:
    numerator += dict1[n_gram] * dict2[n_gram]
    denom1 += dict1[n_gram]**2
    denom2 += dict2[n_gram]**2

print(numerator/(math.sqrt(denom1)*math.sqrt(denom2)))
1个回答

14

浮点数运算可能是确定性的,但是字典键的顺序却不是。

当你调用.keys()时,所得出的列表顺序可能是随机的。

因此,在循环中进行数学运算的顺序也有可能是随机的,因此结果不会是确定性的,因为单个浮点运算的结果可能是确定性的,但一系列操作的结果非常依赖于顺序。

通过对键列表进行排序,您可以强制执行一致的顺序。


Python 3.x 中字典的顺序是不确定的,除非在 Python 2.x 中明确配置。 - thefourtheye
那么,您会推荐强制排序还是只将其保留在“浮点数不精确,没关系”的类别中?我只会盯着这些数据看。如果这些数据将在后续的计算中使用,您会改变您的答案吗? - John Montgomery
2
我通常会将其留在“浮点数不精确”的领域。 - Amber

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