2012-01-12 63 views
2

首先,我不是一个数学家,所以大量的精度很少过滤到我的日常工作中。请温柔。 )Python 32/64位机器浮点移位矩阵求和不正确?

使用NumPy的,以产生具有从值1相等地划分的矩阵:

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

在64位的Windows与Python 2.6,求和很少工程以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 <总和(M)< +小量),但我想先了解一下该差异的原因是内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 

这将设置矩阵机数来表示在我的Windows测试32位浮点,不64位,并且将正确总结。为什么0.001浮点数不等于32位和64位系统上的机器编号?如果我试图存储具有许多小数位的非常小的数字,我希望它们会有所不同。

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

+4

您*必须*使用ε,因为你必须永远* *比较浮点数的确切平等。 *特别*你知道的数字是算术的结果,而不是例如。常量或配置值,例如。 – unwind 2012-01-12 16:55:52

+0

@unwind:永远不要说永远。精确的相等测试有时在浮点上是合适和必要的。但是,这不是其中之一。 – 2012-01-12 16:57:46

+0

您可能想了解[浮点数](http://en.wikipedia.org/wiki/Floating_point)是如何工作的。知道什么时候做什么是很有用的。 – murgatroid99 2012-01-12 17:03:22

回答

2

这是因为你比较32位浮点64位浮点,因为你已经发现了。

如果指定在两台机器上32位或64位D型,你会看到同样的结果。

numpy的默认浮点D型细胞(数值类型为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()) 

会有所不同,由于不同的精度,但你会看到在不同的机器相同的结果。 (然而,64位的操作会比较慢在32位机器上)

如果你只是指定numpy.float,这将是要么依赖于计算机的本地架构的float32float64

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 
+0

这也可以做到。这个人只是让我想改变我的问题。十进制应该精确地表示数值。但是在32位和64位浮点数之间,为什么0.001浮点数不能等同地表示为机器号? – garlicman 2012-01-12 17:14:34

+0

哦,我同意,十进制不是很有效。在使用小数之前,我会切换到epsilon,但是谢谢您的建议! – garlicman 2012-01-12 17:18:46

+1

有关python中浮点运算的更多信息,您可能需要查看[here](http://docs.python.org/tutorial/floatingpoint.html)。 – jcollado 2012-01-12 17:30:37

2

首先,如果您使用numpy的存储值,你应该使用numpy的的方法,如果提供,以处理阵列/矩阵。也就是说,如果你想要相信那些把numpy放在一起的非常有能力的人。

现在,numpy的sum()的64位答案无法精确到1,因为计算机中处理浮点数的原因(murgatroid99为您提供了一个链接,还有数百个链接) 。 因此,唯一安全的方法,(甚至对理解你的代码的数学处理更好,因此你的问题本身也非常有帮助)就是使用一个epsilon值以一定的精度截断。

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

因此,有可能其他的方法来处理它,但大多数的时候,我会用的ε来确定我需要一个给定的问题的精度。