numpy中的精度:比较数字时的问题

4 投票
4 回答
4751 浏览
提问于 2025-04-17 09:52

先说一下背景。我正在寻找一个实对称矩阵的特征值和特征向量,这个矩阵的每一行的和都等于0。更具体地说,一旦我找到一个特征向量,我就用 $argsort$ 来找出一个排序的顺序,然后把这个顺序应用到原始矩阵上。

现在,我在 Python 中实现了这个代码,使用了 numpy 这个库。这个代码是递归的,如果它在特征向量中找到一组相等的值,它就会提取出对应于这些相等值的对称子矩阵,然后在这个子矩阵上再次应用这个算法。

虽然这一切都很好,主要是一些繁琐的工作,但当我发现一堆应该对应特征向量中相等条目的索引没有被识别为相等时,我感到很惊讶。问题在于,这些值是通过某个算法(可能是 Lanczos,但我对 numpy 不是很熟悉)计算到机器精度的。这是一个示例输出,我在其中明确检查了特征向量中两个条目之间的差异:

    >>> T=spectral.seriation(A,index)

    columns [ 0  1  2  3  4  5  6  7  8  9 10 11]

    [  3.30289130e-01  -2.75240941e-01  -2.75240941e-01   3.30289130e-01
    -2.75240941e-01   3.30289130e-01  -2.75240941e-01   3.30289130e-01
    3.30289130e-01  -2.75240941e-01  -1.69794463e-16  -2.75240941e-01]

    [ 4  6  9  1  2 11 10  0  5  7  8  3]

    difference   -5.55111512313e-17

这个 routine seriation() 是一个递归函数。浮点数组是正在考虑的特征向量,而下面的数组给出了列的排序顺序。注意,列 [4,6,9,1,2,11] 的值是相同的。然而,特征向量和特征值的计算总是近似的,实际上,当我输出第 9 列和第 2 列之间的差异时,它并不为零。算法应该把 [4,6,9,1,2,11] 分到一组,但它只把 [4,6,9] 分到一组,把其余的放到另一组,这就给工作带来了麻烦。

所以问题是:在 numpy 中有没有方法可以进行任意精度的计算?如果没有,那有什么“好”的解决办法呢?

另外,我可能还应该提到,这些条目必须相等是可以通过数学证明的。这是矩阵的一个性质,但希望这与问题无关。

4 个回答

3

在对两个大小相近的浮点数进行减法运算时,精度通常不会成为问题。也就是说,如果[2]和[9]确实是相同的,那么它们的差值应该是零。

我怀疑实际情况是,默认情况下输出的数字显示到小数点后8位,但实际上这些数字在小数点后8位以外是不同的。通常,一个双精度浮点数大约有16位小数的精度(如果想知道,可以运行numpy.finfo(numpy.float).eps来获取机器的最小精度值,这个值是大于1的最小可能数字)。

你可以尝试用"%.16f\n%.16f" % myarray[[2, 9]]这种格式来查看这些数字。

如果它们确实不同,但你对小数点后7位的相似度感到满意,那么可以使用numpy.around(differences, 7)来截断结果。

另外,如果你想提前处理数据,可以使用类似下面的方式(虽然可能还有更好的方法)。

sigcnd, expn = numpy.frexp(myarray)
sigcnd = numpy.around(sigcnd, 7)
truncated_myarray = numpy.ldexp(sigcnd, expn)
4

可以看看 numpy.allclosenumpy.isclose 这两个函数,它们可以用来检查两个数是否在一个允许的范围内相等。

4

双精度数(doubles)并不完全等同于真实数字(甚至不是有理数)。在每个范围内都有无限多个有理数(准确来说,至少有两个元素的范围),但用来表示它们的位数是有限的。
因此,在进行“精确”计算时,你应该预期会出现一些舍入误差。

想了解更多信息,你可以看看 每个计算机科学家都应该知道的浮点运算知识

撰写回答