Python 32/64位机器浮点求和转置矩阵不正确?

时间:2012-01-12 16:52:56

标签: python math matrix numpy

首先,我不是一个数学家,所以很多精确度很少会过滤到我的日常工作中。请温柔。 ;)

使用NumPy生成一个矩阵,其值均等于1:

>>> m = numpy.matrix([(1.0 / 1000) for x in xrange(1000)]).T
>>> m
matrix[[ 0.001 ],
       [ 0.001 ],
       ...
       [ 0.001 ]])

在使用Python 2.6的64位Windows上,求和很少能达到1.0。 math.fsum()使用这个矩阵,如果我改变矩阵使用较小的数字则不行。

>>> numpy.sum(m)
1.0000000000000007
>>> math.fsum(m)
1.0
>>> sum(m)
matrix([[ 1.]])
>>> float(sum(m))
1.0000000000000007

在使用Python 2.6的32位Linux(Ubuntu)上,求和总是可以达到1.0。

>>> numpy.sum(m)
1.0
>>> math.fsum(m)
1.0
>>> sum(m)
matrix([[ 1.]])
>>> float(sum(m))
1.0000000000000007

在评估矩阵总和为1时(例如-epsilon< sum(m)< + epsilon),我可以在我的代码中添加一个epsilon但是我想先了解差异的原因是什么,在Python中,如果有更好的方法来正确确定总和。

我的理解是,总和处理数字(浮点数)的机器表示不同于它们的显示方式,并且当求和时,使用内部重复。但是,看看我用来计算总和的3种方法,不清楚为什么它们都是不同的,或者平台之间是相同的。

正确计算矩阵之和的最佳方法是什么?

如果您正在寻找更有趣的矩阵,这个简单的更改将具有更小的矩阵数:

>>> m = numpy.matrix([(1.0 / 999) for x in xrange(999)]).T

提前感谢您的帮助!

更新 我想我想出了什么。如果我将存储的值更正为32位浮点数,则结果与32位Linux求和相匹配。

>>> m = numpy.matrix([(numpy.float32(1.0) / 1000) for x in xrange(1000)]).T
>>> m
matrix[[ 0.001 ],
       [ 0.001 ],
       ...
       [ 0.001 ]])
>>> numpy.sum(m)
1.0

这将设置矩阵机器编号以表示32位浮点数,而不是我的Windows测试中的64位浮点数,并将正确求和。为什么0.001浮点数不等于32位和64位系统上的机器号?如果我试图存储带有大量小数位的非常小的数字,我希望它们会有所不同。

有没有人对此有任何想法?在这种情况下,我应该明确切换到32位浮点数,还是有64位求和方法?还是我回来添加一个epsilon?对不起,如果我听起来很愚蠢,我对意见很感兴趣。谢谢!

3 个答案:

答案 0 :(得分:2)

我会说最准确的方法(不是最有效的方法)是使用decimal module

>>> from decimal import Decimal
>>> m = numpy.matrix([(Decimal(1) / 1000) for x in xrange(1000)])
>>> numpy.sum(m)
Decimal('1.000')
>>> numpy.sum(m) == 1.0
True

答案 1 :(得分:2)

首先,如果使用numpy存储值,则应使用numpy的方法(如果提供)来处理数组/矩阵。也就是说,如果你想要相信能够把numpy放在一起的非常有能力的人。

现在,numpy的sum()的64位答案不能总结为1,因为计算机中的浮点数是如何处理的(murgatroid99为你提供了一个链接,那里有数百个)。 因此,唯一安全的方法(甚至非常有助于理解你的代码的数学处理更好,因此你的问题本身)是使用epsilon值以一定的精度切断。

为什么我认为它有用?因为计算科学需要像实验科学一样处理错误,并且在这个地方故意处理(意思是:确定它们)错误,所以你已经完成了处理代码计算错误的第一步。

所以,可能有其他方法来处理它,但大多数时候,我会使用epsilon来确定给定问题所需的精度。

答案 2 :(得分:2)

这是因为你正在比较32位浮点数和64位浮点数,正如你已经发现的那样。

如果在两台计算机上指定32位或64位dtype,您将看到相同的结果。

Numpy的默认浮点dtype(numpy数组的数值类型)与机器精度相同。这就是为什么你在不同的机器上看到不同的结果。

E.g。 32位版本:

m = numpy.ones(1000, dtype=numpy.float32) / 1000
print repr(m.sum())

和64位版本:

m = numpy.ones(1000, dtype=numpy.float64) / 1000
print repr(m.sum())

由于精度不同会有所不同,但您会在不同的机器上看到相同的结果。 (但是,在32位计算机上,64位操作将 更慢)

如果您只是指定numpy.float,则可能是float32float64,具体取决于计算机的本机架构。