在朱莉娅,我有一系列像这样的布尔人:
3×5 Array{Bool,2}:
true false true false true
true true true true false
false false true true false
除了我有超过三行。例如,计算第二列和第四列true
的行数以及第二列和第三列为真的行数的最快/最佳方法是什么?现在我有这样的事情,其中N
是行数:
num_2and3true = 0
num_2and4true = 0
for i = 1:N
if m[i,2] == 1
if m[i,3] == 1
num_2and3true += 1
end
if m[i,4] == 1
num_2and4true += 1
end
end
end
有更快的方法吗?我有一种预感,我这样做的方式太简单了,不是最好的方法。感谢....
答案 0 :(得分:4)
问题中的计算确实很简单,也非常优秀。我发现的一点点改进是:
num_2and3true = 0
num_2and4true = 0
for i = indices(m,1)
num_2and3true += Int(m[i,2] && m[i,3])
num_2and4true += Int(m[i,2] && m[i,4])
end
我的机器速度提高了约20%。可能是因为支化减少了。要测试我是否使用了随机m
,但结果可能因特定m
(尺寸和内容)而异。
为了获得更好的性能,请在for
和@inbounds
之前添加,这样可以避免在数组访问中出现一些越界错误检查:
@inbounds for i = indices(m,1)
更好的是,添加@simd
,以便在可能的CPU支持下使用SIMD指令:
@inbounds @simd for i = indices(m,1)
导致:
num_2and3true = 0
num_2and4true = 0
@inbounds @simd for i = indices(m,1)
num_2and3true += Int(m[i,2] && m[i,3])
num_2and4true += Int(m[i,2] && m[i,4])
end
比问题版本快10倍(再次,在我的机器上)。
更新:请参阅评论,原因indices(m,1)
优于1:size(m,1)
。
更新:将Bool转换为0/1整数(感谢DNF的评论),使代码更清晰。
使用不同方法添加了另一个答案(速度提高了3倍)。这个答案可能更清楚。
答案 1 :(得分:2)
更快但不同的方法是使用BitVectors来压缩Bool向量并使用单个AND指令来替换64个逻辑AND运算。当然,这需要分配一些内存,但事实证明,它的好处超过了成本,而且它的出现速度更快( caveat emptor ,在我的机器上)。功能是:
function bar(m)
num_2and3true = 0
num_2and4true = 0
v2 = BitVector(view(m,:,2))
v3 = BitVector(view(m,:,3))
v4 = BitVector(view(m,:,4))
num_2and3true += sum(v2 .& v3)
num_2and4true += sum(v2 .& v4)
return (num_2and3true, num_2and4true)
end
答案 2 :(得分:1)
我从simd
获得的加速度不高。这是我发现的最快的版本(实际上,Int
产生了一些小的差异):
function foo(m)
n23 = n24 = 0
@inbounds for i in indices(m, 1)
!m[i, 2] && continue
n23 += Int(m[i, 3])
n24 += Int(m[i, 4])
end
return n23, n24
end
我在m = rand(Bool, 1000, 5)
上对此进行了测试。请注意,由于分支,你不能在这里使用@simd
,但正如我所说,@simd
对我来说做的很少。
替代方案是:
function bar(m)
n23 = n24 = 0
@inbounds @simd for i in indices(m, 1)
n23 += Int(m[i, 2] && m[i, 3])
n24 += Int(m[i, 2] && m[i, 4])
end
return n23, n24
end
编辑:我看到一个非常奇怪的事情:如果我将!m[i, 2] && continue
替换为m[i, 2] || continue
,我会看到3倍的减速。可能导致什么?