![](/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.