看来你无法决定性能和浮点精度哪个更重要。
如果浮点精度是最重要的精度,那么您将隔离正元素和负元素,对每个段进行排序。然后按绝对值递增的顺序求和。是的,我知道,这比任何人都会做的工作要多,而且可能会浪费时间。
相反,使用足够的精度,这样所犯的任何错误都无关紧要。使用关于测试等的良好数值实践,这样就不会产生问题。
就时间而言,对于 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)) 相比,我所展示的任何替代方案都更加耗时。只需选择其中之一即可,不用担心。