让矩阵A
说A = magic(100);
。我已经看到了两种计算矩阵A
的所有元素之和的方法。
sumOfA = sum(sum(A));
或者
sumOfA = sum(A(:));
其中一个比其他更快(或更好的练习)吗?如果是这样的话呢?或者他们都同样快?
答案 0 :(得分: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(:))视为随机游走,醉汉的行走。但考虑总和(总和(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))相比,我所展示的任何替代方案都要花费更多的时间。只需选择其中一个,不要担心。
答案 1 :(得分: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
较大矩阵的误差幅度增加
答案 2 :(得分:1)
我认为一种简单的理解方法是在代码的第一和最后加上“ tic_ toc ”功能。
tic
A = randn(5000);
format long g
sum(A(:));
toc
但是当您使用randn函数时,其元素是随机的,计算时间可以 在每个周期 CPU 计算中各不相同。 这样更好,您可以使用独特的矩阵白色元素,以便比较计算时间。