矩阵乘法精度 Matlab vs Python

计算科学 matlab 矩阵 Python 浮点 准确性
2021-12-03 17:24:28

我正在将一些 Matlab 代码翻译成 Python,并且在矩阵乘法精度方面遇到了一些问题。假设我们有以下数据:

A: 6x6 matrix
B: 5x5 matrix
C: 2x2 matrix
D: 5x5 matrix
E: 6x5 matrix

在 Matlab 中,我的操作如下所示:

R1 = A * (-( B*C(1,1) + D*C(2,1) ) * E.').'

上一组操作产生一个 6x5 矩阵(R1 矩阵)。

在我的 Python 代码中,我有相同的矩阵,操作如下所示:

R2 = np.matmul(A, np.matmul(-(np.multiply(B, C[0,0]) + np.multiply(D, C[1,0])), E.transpose()).transpose())

但是,对相同数据的相同操作会在 方面产生不同的结果norm-2,即:

norm-2(R1-R2) = 7.4506e-09

我无法理解为什么结果不同。有谁知道可能是什么原因?

为了清楚起见,我在此处附上数据和脚本。指令是:

  1. 运行 Run_python.py 脚本。这将执行操作并生成一个 python_results.mat 文件。
  2. 运行 Run_matlab 脚本。这将执行操作并将根据其 norm-2 比较两个结果。

最后,我的 Python 版本是 3.6.3,带有 numpy (1.14.3) 和 scipy (1.1.0)。

2个回答

这是R1,在 MATLAB 中计算:

   1.0e+07 *
  -7.382605957465515  -9.599867106092937  -2.830412177259742  -0.000000000002830  -0.000000000002830
  -1.230434326244253  -1.599977851015490  -0.471735362876624  -0.000000000000472  -0.000000000000472
   3.691302978732758   4.799933553046468   1.415206088629871   0.000000000001415   0.000000000001415
  -5.056592907133381  -6.575268976533256  -1.938643647277773  -0.000000000001939  -0.000000000001939
  -2.842303293624223  -3.695948835845781  -1.089708688245001  -0.000000000001090  -0.000000000001090
  -2.522882542531216  -3.280594585722160  -0.967246188042229  -0.000000000000967  -0.000000000000967

norm(R1) = 1.76e8(最大奇异值)

的剩余奇异值R1,每个 MATLAB 双精度,范围从1.48e-8下到1.57e-37所以R1是极度病态的。

鉴于norm(R1) = 1.76e8,您不能期望norm(R1)比观察到的 MATLAB 到 PYTHON 更准确(由于三角不等式norm(R1-R2) = 7e-9,这已经可能是误差的两倍)。norm(R1)总而言之,对于具有机器精度的双精度,您已经比最坏情况好一个数量级2.2e-16

首先,请参阅 Mark L. Stone 的答案,这是完全正确的。其次,要意识到这就是人们告诉你在数值分析课上使用相对误差的原因。:)

第三,这里真正的问题是为什么结果不完全一致,因为两种语言都调用一些 BLAS 库函数进行计算。发生这种情况有几个非常特定于 BLAS 的原因:

  • Matlab 和 Python 可能链接到不同版本的 BLAS 库。它们不能保证在最后一位之前产生完全相同的结果。不同的优化可以以不同的方式重新排列总和(使用关联性),并给出略有不同的结果。有关详细信息,请参阅https://bebop.cs.berkeley.edu/reproblas/ 。
  • Matlab 包含检测,形式A*B'乘法并将它们映射到单个 BLAS 调用的特殊技巧。我不确定 Python 是否也这样做,如果这样做,它可能会在使用类似的东西时将它们映射到稍微不同的调用。A*B.'A*A'(A*B.').'
  • 两种语言都可能包括优化映射A*B位置A和/或B对称到专门的 BLAS 调用 ( DSYMM)。同样,这可能在两种语言中以略微不同的方式实现,并且可能还取决于先前计算的结果。