9

让矩阵AA = magic(100);。我已经看到了两种计算矩阵所有元素之和的方法A

sumOfA = sum(sum(A));

或者

sumOfA = sum(A(:));

其中一个比另一个更快(或更好的练习)吗?如果有,是哪一个?还是它们都同样快?

4

3 回答 3

15

似乎您无法决定性能还是浮点精度更重要。

如果浮点精度是最重要的精度,那么您将分离正负元素,对每个段进行排序。然后按照绝对值递增的顺序求和。是的,我知道,它的工作量比任何人都多,而且可能会浪费时间。

相反,请使用足够的精度,以使所犯的任何错误都无关紧要。使用关于测试等的良好数值实践,这样就不会产生问题。

就时间而言,对于 NxM 阵列,

sum(A(:)) 将需要 N*M-1 加法。

sum(sum(A)) 将需要 (N-1)*M + M-1 = N*M-1 加法。

任何一种方法都需要相同数量的添加,所以对于一个大数组,即使解释器不够聪明,无法识别它们都是同一个操作,谁在乎呢?

这根本不是问题。不要为了担心这个而把鼹鼠山变成一座山。

编辑:为了回应 Amro 关于一种方法的错误的评论,您几乎无法控制。添加将以不同的顺序完成,但不能保证哪个顺序会更好。

A = randn(1000);
format long g

这两种解决方案非常接近。事实上,与 eps 相比,差异几乎不显着。

sum(A(:))
ans =
          945.760668102446

sum(sum(A))
ans =
          945.760668102449

sum(sum(A)) - sum(A(:))
ans =
      2.72848410531878e-12

eps(sum(A(:)))
ans =
      1.13686837721616e-13

假设您选择我提到的隔离和排序技巧。请注意,负部分和正部分将足够大,以至于会损失精度。

sum(sort(A(A<0),'descend'))
ans =
          -398276.24754782

sum(sort(A(A<0),'descend')) + sum(sort(A(A>=0),'ascend'))
ans =
            945.7606681037

因此,无论如何,您确实需要将这些片段累积在更高精度的数组中。我们可以试试这个:

[~,tags] = sort(abs(A(:)));
sum(A(tags))
ans =
          945.760668102446

即使在这些测试中也会出现一个有趣的问题。是否会因为测试是在随机(正常)阵列上完成而出现问题?本质上,我们可以将 sum(A(:)) 视为随机游走,醉汉游走。但是考虑 sum(sum(A))。sum(A) 的每个元素(即内部和)本身就是 1000 个正态偏差的总和。看看其中几个:

sum(A)
ans =
  Columns 1 through 6
         -32.6319600960983          36.8984589766173          38.2749084367497          27.3297721091922          30.5600109446534          -59.039228262402
  Columns 7 through 12
          3.82231962760523          4.11017616179294         -68.1497901792032          35.4196443983385          7.05786623564426         -27.1215387236418
  Columns 13 through 18

当我们将它们相加时,精度会有所下降。因此,作为 sum(A(:)) 的操作可能会更准确一些。是这样吗?如果我们使用更高的精度进行累加呢?因此,首先,我将使用双精度对列求和,然后转换为 25 位小数精度,并对行求和。(我在这里只显示了 20 个数字,留下 5 个数字作为保护数字隐藏。)

sum(hpf(sum(A)))
ans =
945.76066810244807408

或者,立即转换为 25 位精度,然后对结果求和。

sum(hpf(A(:))
945.76066810244749807

所以双精度的两种形式在这里同样是错误的,方向相反。最后,这一切都没有实际意义,因为与简单的变化 sum(A(:)) 或 sum(sum(A)) 相比,我展示的任何替代方案都更耗时。只需选择其中一个,别担心。

于 2012-07-01T15:05:19.323 回答
3

在性能方面,我想说两者都非常相似(假设是最近的 MATLAB 版本)。这是使用TIMEIT功能的快速测试:

function sumTest()
    M = randn(5000);
    timeit( @() func1(M) )
    timeit( @() func2(M) )
end
function v = func1(A)
    v = sum(A(:));
end
function v = func2(A)
    v = sum(sum(A));
end

结果是:

>> sumTest
ans =
    0.0020917
ans =
    0.0017159

我担心的是浮点问题。例子:

>> M = randn(1000);
>> abs( sum(M(:)) - sum(sum(M)) )
ans =
   3.9108e-11

对于较大的矩阵,误差幅度会增加

于 2012-07-01T08:56:23.077 回答
0

我认为一个简单的理解方法是在代码的第一个和最后一个应用“ tic_ toc ”函数。

tic
A = randn(5000);
format long g
sum(A(:));
toc

但是当你使用 randn 函数时,它的元素是随机的,并且每个周期CPU计算的计算时间可能不同。这更好地使用了一个具有如此大元素的独特矩阵来比较计算时间。

于 2018-10-22T13:54:35.373 回答