提问人:Ofri Sadowsky 提问时间:5/15/2023 最后编辑:Ofri Sadowsky 更新时间:5/22/2023 访问量:71
Matlab根据计算形式产生不同的矩阵乘积结果
Matlab produces different matrix product results depending on computation form
问:
在 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 ~= prod2
prod1 == prod2
>> max(max(abs(prod2 - prod1)))
ans =
1.1102e-16
这种差异等于在“较弱”的计算机上,而在我的“强大”计算机上的差异为非零。0
我想在某些计算机上发生这种情况而不是在其他计算机上发生的原因是,在发生这种情况的地方,矩阵乘法有一些硬件加速(可能涉及三元运算,因这种差异而臭名昭著)。madd
这是一些已知问题,例如“错误”吗? 是否有解决方法,例如禁用或暂停这种硬件加速?
作为单元测试的一部分,我正在寻求在不同计算机上获得相同的计算结果。我可以满足于“近乎平等”。但如果我能得到真正的平等,我就不应该这样做。
编辑 1
我强调的核心问题是,完全相同的语法表达式在不同的计算机上产生不同的结果,而明显的原因是在不同的计算机上进行了不同的计算优化。位身份是一个不能被抛弃的要求。我希望这两个平台(基于 64 位 intel 的 Windows 10)能够为完全相同的输入和表达式计算完全相同的结果。
编辑 2
我试图提取结果不同的输入的特定元素(即.我将它们收集到一个矩阵中,以便对它们重复计算。哇!这次的结果与 中不同。它更类似于显式迭代案例。prod2(k,:) ~= prod1(k,:)
prod1
很抱歉,我无法在本次讨论的范围内完全重现该问题。但我们可以再讨论一些。
我会检查张的线程问题。我什至会尝试重复计算几次,看看差异是否出现在同一位置。如果是关于多线程的,我希望差异会出现在非确定性索引中。
答:
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.
评论
M * R
M
R
P_i = M_i * R
which mtimes
prod1
prod2
The official response from MathWorks tech support points to these links:
- An answer to a similar question explaining that the details of computation order are in the LAPACK library, and, therefore, not tunable from Matlab.
- 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.
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.eps
tol
eps(x)
x
x
x
eps
tol = 10
Since you are talking about unit tests, you might be using MATLAB's Testing Framework, in which case you'd use verifyEqual
.
评论
eps('double')
和 stackoverflow.com/q/686439/3978545