Matlab根据计算形式产生不同的矩阵乘积结果

Matlab produces different matrix product results depending on computation form

提问人:Ofri Sadowsky 提问时间:5/15/2023 最后编辑:Ofri Sadowsky 更新时间:5/22/2023 访问量:71

问:

在 Matlab 中,我以两种方式计算 2D 点集合的旋转:一种通过正矩阵矩阵乘积,另一种通过迭代向量矩阵积,如下所示。

>> points = % read data from some file, Nx2 matrix
>> R = [cosd(-18), sind(-18); -sind(-18), cosd(-18)];  % My rotation matrix
>> prod1 = points * R;
>> numpt = size(points, 1);
>> for k=1:numpt, prod2(k,:) = points(k,:) * R; end;

我正在使用装有 Windows 10 操作系统的“常规”(基于英特尔)PC。

事实证明,在某些计算机上,和其他计算机上,.这可以通过以下方式进行检查prod1 ~= prod2prod1 == prod2

>> max(max(abs(prod2 - prod1)))

ans =

   1.1102e-16

这种差异等于在“较弱”的计算机上,而在我的“强大”计算机上的差异为非零。0

我想在某些计算机上发生这种情况而不是在其他计算机上发生的原因是,在发生这种情况的地方,矩阵乘法有一些硬件加速(可能涉及三元运算,因这种差异而臭名昭著)。madd

这是一些已知问题,例如“错误”吗? 是否有解决方法,例如禁用或暂停这种硬件加速?

作为单元测试的一部分,我正在寻求在不同计算机上获得相同的计算结果。我可以满足于“近乎平等”。但如果我能得到真正的平等,我就不应该这样做。

编辑 1

我强调的核心问题是,完全相同的语法表达式在不同的计算机上产生不同的结果,而明显的原因是在不同的计算机上进行了不同的计算优化。位身份是一个不能被抛弃的要求。我希望这两个平台(基于 64 位 intel 的 Windows 10)能够为完全相同的输入和表达式计算完全相同的结果。

编辑 2

我试图提取结果不同的输入的特定元素(即.我将它们收集到一个矩阵中,以便对它们重复计算。哇!这次的结果与 中不同。它更类似于显式迭代案例。prod2(k,:) ~= prod1(k,:)prod1

很抱歉,我无法在本次讨论的范围内完全重现该问题。但我们可以再讨论一些。

我会检查张的线程问题。我什至会尝试重复计算几次,看看差异是否出现在同一位置。如果是关于多线程的,我希望差异会出现在非确定性索引中。

MATLAB 矢量化 精密 数值 硬件加速

评论

3赞 Wolfie 5/15/2023
“真正的相等”在机器精度以下不存在,1e-16 是一个比使用数字双精度可以准确表示的误差更小的误差,参见 eps('double')stackoverflow.com/q/686439/3978545
1赞 Cris Luengo 5/17/2023
不要期望相同的结果,期望相同的结果,但舍入误差不同。
0赞 Ofri Sadowsky 5/17/2023
恐怕两条评论都错过了这个问题。核心问题是,在不同的平台上,具有相同输入的完全相同的语法表达式被评估为不同的结果。明显的原因是,一个平台对评估的优化与另一个平台不同。位标识有时(并非总是)是一项要求。它不应该被挥手而去。我寻求的是在测试代码时禁用优化的选项,以便不同的平台产生相同的结果。
0赞 Cris Luengo 5/17/2023
它不是关于优化,而是关于计算顺序和内部细节。我可以用 C 语言编写代码,结果会因我使用的编译器、传递给编译器的标志、目标平台等而产生微小差异。使用浮点计算时,您永远不应该期望获得相同的结果。把这个想法从你的脑海中抹去,它不会发生。你应该得到的相等结果,你不会得到相同的结果。
0赞 Ofri Sadowsky 5/17/2023
我不确定你的确切意思。我目前的情况是,我有一个单元测试,它不能在具有(几乎)相同操作系统和处理器类型的不同主机之间移植。我可以让它工作,但我认为它不应该是这样的。使用相同输入的相同操作在一台主机上生成一个结果,在另一台主机上生成另一个结果。

答:

0赞 X Zhang 5/17/2023 #1

Each variable in each step need to be verified to answer all the questions. In general, the result should be the same for well-defined math functions across platforms. Meanwhile, you can leverage on the symbolic toolbox to increase precision of numeric calculations.

评论

0赞 Ofri Sadowsky 5/17/2023
You may read the recent edit of the question. The same syntactical expression with the same input produces different results on different platforms.
0赞 X Zhang 5/17/2023
@OfriSadowsky Can you pinpoint when the difference first appeared along the processing pipeline? e.g. after Line 1, or Line 2, etc. Also matlab can be configured to various precision, can you reset both computers to factory defaults?
0赞 Ofri Sadowsky 5/17/2023
The difference appears between computing an expression of the form , where is a matrix of size Nx2 and is a matrix of size 2x2, and computing , where i is the row index and the computation is via explicit iteration over the rows instead of whole matrix multiplication. The outcome of the row-wise iteration on host H1 differs from the outcome of the whole matrix multiplication on H1, but it is equal to the outcome of whole matrix multiplication on host H2. Equality meaning bit identity here. I will resort to epsilon comparison if there is no other choice.M * RMRP_i = M_i * R
0赞 X Zhang 5/17/2023
@OfriSadowsky Oh. Similar to this one. Epsilon might be the way to go. Another unlikely possibility is the mtimes function being deeply overloaded by unusual toolboxes. might help.which mtimes
0赞 Ofri Sadowsky 5/17/2023
Just to clarify wrt Zhang's question: The first block in my question creates two objects: and , both matrices of equal size and almost equal content. The difference shows up in my second code block. I will prepare some specific data for which the differences show up.prod1prod2
1赞 Ofri Sadowsky 5/22/2023 #2

The official response from MathWorks tech support points to these links:

  1. An answer to a similar question explaining that the details of computation order are in the LAPACK library, and, therefore, not tunable from Matlab.
  2. An example from the Symbolic Toolbox that shows how to improve overall precision, with the price being the Symbolic Toolbox itself, a new code that uses it, and computation time increase.

Given this, my preference is to round the computation outcome. As explained in the conversations, my goal is repeatability, not precision. And it looks like the most cost effective answer here is rounding.

0赞 Cris Luengo 5/22/2023 #3

Floating-point operations incur a rounding error. The order of operations, which changes depending on platform, compiler, compiler options, etc., affects the rounding error. So, internal MATLAB operations will produce slightly different results from one version of MATLAB to another, and from one platform to another, and between different ways of expressing the same value. You simply cannot expect two floating-point arrays to be identical.

So, instead of comparing two arrays using the operation, which requires them to be identical, you want to compare them with a tolerance. One way to do so is:==

tol = 10
all( abs(prod1 - prod2) < tol * eps(max(abs(prod1),[],'all')) ,'all')
%    ^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
%    absolute difference              tolerance

Here we are ensuring that the absolute difference between the two arrays is less than some tolerance, for all array elements.

The tolerance is constructed by taking the for the maximum absolute value of the array, and scaling that with a parameter that you set yourself. is the smallest value you can add to such that it is no longer equal to . That is, it is the precision of the value . A rounding error is always within , but rounding errors can accumulate, so you might want to start with as in the example above.epstoleps(x)xxxepstol = 10

Since you are talking about unit tests, you might be using MATLAB's Testing Framework, in which case you'd use verifyEqual.