![](/img/trans.png)
[英]What is the difference between MATLAB/Octave corr and Python numpy.correlate?
[英]Matlab/Octave/Numpy numeric difference
我正在移植一个在Matlab中工作的算法,以便numpy并观察到一个奇怪的行为。 相关的代码段是
P = eye(4)*1e20;
A = [1 -0.015 -0.025 -0.035; 0.015 1 0.035 -0.025; 0.025 -0.035 1 0.015; 0.035 0.025 -0.015 1];
V1 = A*(P*A')
V2 = (A*P)*A'
当我使用Matlab运行时,此代码提供以下矩阵:
V1 = 1.0021e+20 0 -8.0000e+00 0
0 1.0021e+20 0 0
-8.0000e+00 0 1.0021e+20 0
0 0 0 1.0021e+20
V2 = 1.0021e+20 0 -8.0000e+00 0
0 1.0021e+20 0 0
-8.0000e+00 0 1.0021e+20 0
0 0 0 1.0021e+20
请注意,V1和V2与预期相同。
当相同的代码在Octave中运行时,它提供:
V1 = 1.0021e+20 4.6172e+01 -1.3800e+02 1.8250e+02
-4.6172e+01 1.0021e+20 -1.8258e+02 -1.3800e+02
1.3801e+02 1.8239e+02 1.0021e+20 -4.6125e+01
-1.8250e+02 1.3800e+02 4.6125e+01 1.0021e+20
V2 = 1.0021e+20 -4.6172e+01 1.3801e+02 -1.8250e+02
4.6172e+01 1.0021e+20 1.8239e+02 1.3800e+02
-1.3800e+02 -1.8258e+02 1.0021e+20 4.6125e+01
1.8250e+02 -1.3800e+02 -4.6125e+01 1.0021e+20
在numpy,该细分市场成为
from numpy import array, dot, eye
A = numpy.array([[1, -0.015, -0.025, -0.035],[0.015, 1, 0.035, -0.025],[0.025, -0.035, 1, 0.015],[0.035, 0.025, -0.015, 1]])
P = numpy.eye(4)*1e20
print numpy.dot(A,numpy.dot(P,A.transpose()))
print numpy.dot(numpy.dot(A,P),A.transpose())
哪个输出
[[ 1.00207500e+20 4.61718750e+01 -1.37996094e+02 1.82500000e+02]
[ -4.61718750e+01 1.00207500e+20 -1.82582031e+02 -1.38000000e+02]
[ 1.38011719e+02 1.82386719e+02 1.00207500e+20 -4.61250000e+01]
[ -1.82500000e+02 1.38000000e+02 4.61250000e+01 1.00207500e+20]]
[[ 1.00207500e+20 -4.61718750e+01 1.38011719e+02 -1.82500000e+02]
[ 4.61718750e+01 1.00207500e+20 1.82386719e+02 1.38000000e+02]
[ -1.37996094e+02 -1.82582031e+02 1.00207500e+20 4.61250000e+01]
[ 1.82500000e+02 -1.38000000e+02 -4.61250000e+01 1.00207500e+20]]
所以,Octave和numpy都提供了相同的答案,但它与Matlab的非常不同。 第一点是V1!= V2,这似乎不对。 另一点是,尽管非对角线元素比对角线元素小许多个数量级,但这似乎在我的算法中引起了一些问题。
有谁知道方式numpy和Octave这样做?
它们在内部使用双精度,只有大约15位数的精度。 您的数学运算可能超过此值,这会导致数学上错误的结果。
值得一读: http : //floating-point-gui.de/
编辑:从我收集的文档中可以看出Numpy没有更高的精度。 似乎SymPy 可能会给你所需的精度 - 如果该库也适合你。
无论它值多少,我在64位系统上得到与matlab相同的结果:
[[ 1.00207500e+20 0.00000000e+00 -8.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 1.00207500e+20 0.00000000e+00 0.00000000e+00]
[ -8.00000000e+00 0.00000000e+00 1.00207500e+20 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00207500e+20]]
[[ 1.00207500e+20 0.00000000e+00 -8.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 1.00207500e+20 0.00000000e+00 0.00000000e+00]
[ -8.00000000e+00 0.00000000e+00 1.00207500e+20 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00207500e+20]]
[[ 1.00207500e+20 0.00000000e+00 -8.00000000e+00 0.00000000e+00]
如果您使用的是32位系统(或者您在64位系统上安装了32位版本的python和numpy),那么您将遇到精确问题,并获得不同的答案,如@Lucero所述下面。 在这种情况下,您可能会尝试显式指定64位浮点数(但操作会更慢)。 例如,尝试使用np.array(..., dtype=np.float64)
。
如果你认为你需要额外的精密度,你可以使用np.longdouble
(同np.float128
64位系统和np.float96
32位),但是这可能不会在所有平台上和许多线性代数函数的支持将事物截断回本机精度。
另外,你使用什么BLAS库? numpy和octave结果可能相同,因为它们使用相同的BLAS库。
最后,您可以将numpy代码简化为:
import numpy as np
A = np.array([[1, -0.015, -0.025, -0.035],
[0.015, 1, 0.035, -0.025],
[0.025, -0.035, 1, 0.015],
[0.035, 0.025, -0.015, 1]])
P = np.eye(4)*1e20
print A.dot(P.dot(A.T))
print A.dot(P).dot(A.T)
np.einsum
离MATLAB更近了
In [1299]: print(np.einsum('ij,jk,lk',A,P,A))
[[ 1.00207500e+20 0.00000000e+00 -5.07812500e-02 0.00000000e+00]
[ 0.00000000e+00 1.00207500e+20 5.46875000e-02 0.00000000e+00]
[ -5.46875000e-02 5.46875000e-02 1.00207500e+20 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00207500e+20]]
行和列2中的非对角线项不同,但在其他地方具有相同的0。
使用双点, P.dot(AT)
在添加产品时会产生舍入误差。 那些传播到下一个dot
。 einsum
生成所有产品,只需一次总结。 我怀疑MATLAB解释器能够识别这种情况,并执行一项特殊的计算,旨在最大限度地减少舍入误差。
Numpy矩阵乘法U * B * UT结果在非对称矩阵中 - 是一个更近期的问题,具有相同的解释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.