2016-03-23 13 views
4

配列の1つの列を同じ配列の別の列に置き換える必要があるアルゴリズムがあります。 私はスライスや要素ごとにやってみました。配列列のコピー

const M = 10^4 
const N = 10^4 
A = rand(Float32, M, N) 
B = rand(Float32, N, M) 

function copy_col!(A::Array{Float32,2},col1::Int,col2::Int) 
    A[1:end,col2] = A[1:end,col1] 
end 

function copy_col2!(A::Array{Float32,2},col1::Int,col2::Int) 
    for i in 1:size(A,1) 
    A[i,col2] = A[i,col1] 
    end 
end 

[Both functions+rand are called here once for compilation] 

@time (for i in 1:20000 copy_col!(B, rand(1:size(B,2)),rand(1:size(B,2))); end) 
@time (for i in 1:20000 copy_col2!(B, rand(1:size(B,2)),rand(1:size(B,2))); end) 

>> 0.607899 seconds (314.81 k allocations: 769.879 MB, 25.05% gc time) 
>> 0.213387 seconds (117.96 k allocations: 2.410 MB) 

なぜスライスを使用したコピーが非常に悪いですか? copy_col2!より良い方法はありますか?

答えて

7

A[1:end,col1]は、最初にインデックス付き列のコピーを作成してからA[1:end,col2]にコピーします。したがって、copy_col!はmoreを割り当ててより長く実行します。この場合、割り当てを是正できるsub,slice、およびviewがあります。

+0

ありがとう、私はより完全にドキュメントを読む必要があります。実際、 'sub'を使うことは、要素ごとのコピーと同じランタイムを持っています。それでも割り当ては増えますが、それでも問題ありません。洗濯機にも見えます。さらに最適化する方法がわからないでしょうか? – skleinbo

+0

'sub'を使うと他の人が新しいオブジェクトの周りに' A'の列をラップするので、他の人が割り振るのが普通だと思います。要素単位のコピーが使用されている場合、さらに のように '@inbounds'(多分@simdと組み合わせて)で最適化することができます: A [i、col2] 1のiのための@simd @inbounds: = A [i、col1] end ' ' sub 'を使ってメソッドに反映する方法がわかりません。また、A [:、col1] = sub(A、:、col2) 'をしましたか?または、他の何か? –

+0

私はそれを正確に行いました。私はインバウンドとsimdで試して結果を投稿します。しかし、イースターの後。 – skleinbo