在用Fortran08编写的用于计算热力学平衡和相图的大型代码中,我使用了许多对称矩阵,这些矩阵存储为一维数组,并使用一个小函数进行索引
.blog-entry{display: in-line-block}
这很好用,但是在提高了代码其他各个部分的速度之后,此例程现在占用了15-20%的计算时间(它经常使用)。我认为有多种方法可以加快此速度,但是我不知道用C或其他方式可以替代此功能,因此我正在寻求帮助。我使用gfortran,但替换必须是可移植的。
Bo Sundman
答案 0 :(得分:1)
过去,Fortran编译器的性能达到了同等水平或优于C编译器。 因此,我不希望仅通过切换语言而将注意力集中在算法改进上。
如何用查找表替换索引转换的计算?
您是否有存储能力来存储给定的ixsym
和i
索引的j
值?
是的,它可以抵消您对cpu权衡的记忆,但是,如果您有很多矩阵,这可能会有所帮助。
是否真的需要始终计算转换?例如。如果您遍历元素:ixsym(i, j+1) = ixsym(i, j) + 1
,如果i < j
。
尽管特定于硬件,但另一个想法可能是对数据进行不同的排序,以使其保留在CPU的缓存区域内。 (Link)
关于索引转换:
我最初以为您使用了Cantor pairing function的一些变体来枚举对称的2D数组。我问我的朋友露比(Ruby)画几对,她告诉我:
(0, 0) -> 0 (0, 1) -> 0 (0, 2) -> 1 (0, 3) -> 3 (0, 4) -> 6
(1, 0) -> 0 (1, 1) -> 1 (1, 2) -> 2 (1, 3) -> 4 (1, 4) -> 7
(2, 0) -> 1 (2, 1) -> 2 (2, 2) -> 3 (2, 3) -> 5 (2, 4) -> 8
(3, 0) -> 3 (3, 1) -> 4 (3, 2) -> 5 (3, 3) -> 6 (3, 4) -> 9
(4, 0) -> 6 (4, 1) -> 7 (4, 2) -> 8 (4, 3) -> 9 (4, 4) -> 10
我本来应该只计算索引的两次出现,但是我发现某些对出现了三个。这是故意的吗?
更新:
正如其他用户Jean-Claude Arbaut在评论中指出的那样,这是索引的开始。 这是Ruby从1开始的答案:
(1, 1) -> 1 (1, 2) -> 2 (1, 3) -> 4 (1, 4) -> 7 (1, 5) -> 11
(2, 1) -> 2 (2, 2) -> 3 (2, 3) -> 5 (2, 4) -> 8 (2, 5) -> 12
(3, 1) -> 4 (3, 2) -> 5 (3, 3) -> 6 (3, 4) -> 9 (3, 5) -> 13
(4, 1) -> 7 (4, 2) -> 8 (4, 3) -> 9 (4, 4) -> 10 (4, 5) -> 14
(5, 1) -> 11 (5, 2) -> 12 (5, 3) -> 13 (5, 4) -> 14 (5, 5) -> 15
答案 1 :(得分:1)
您可能要考虑的唯一事情就是摆脱该函数中的分支:
两个数字的最小值和最大值可计算为:
max = (a+b + abs(a-b))/2
min = (a+b - abs(a-b))/2 = a+b - max
因此您可以将其用作
integer function ixsym(i,j)
integer :: p, q
q = i+j; p = (q + abs(i-j))/2; q = q - p
ixsym = q + (p*(p-1))/2
return
end
您可以将其进一步简化为
integer function ixsym(i,j)
integer :: p
ixsym = i+j; p = (ixsym + abs(i-j))/2;
ixsym = ixsym + (p*(p-3))/2
return
end