39

OP UPDATE: Juliaの最新バージョン(v0.5)では、この質問に答える慣用的なアプローチは、定義するだけであることに注意してくださいmysquare(x::Number) = x^2。ベクトル化されたケースは、自動ブロードキャストを使用してカバーされますx = randn(5) ; mysquare.(x)。ドット構文をより詳細に説明している新しい回答も参照してください。

私は Julia を初めて使用し、Matlab の出自を考えると、複数のディスパッチと Julia の型システムを利用する「適切な」Julia コードの書き方を判断するのに苦労しています。

a の 2 乗を提供する関数がある場合を考えてみましょうFloat64。私はこれを次のように書くかもしれません:

function mysquare(x::Float64)
    return(x^2);
end

場合によっては、1 次元配列内のすべての s を 2 乗しFloat64たいが、毎回ループを書きたくないmysquareので、複数のディスパッチを使用して次を追加します。

function mysquare(x::Array{Float64, 1})
    y = Array(Float64, length(x));
    for k = 1:length(x)
        y[k] = x[k]^2;
    end
    return(y);
end

しかし、今は時々Int64を使っているので、複数のディスパッチを利用する関数をさらに 2 つ書きます。

function mysquare(x::Int64)
    return(x^2);
end
function mysquare(x::Array{Int64, 1})
    y = Array(Float64, length(x));
    for k = 1:length(x)
        y[k] = x[k]^2;
    end
    return(y);
end

これは正しいですか?または、この状況に対処するためのより理想的な方法はありますか? このような型パラメーターを使用する必要がありますか?

function mysquare{T<:Number}(x::T)
    return(x^2);
end
function mysquare{T<:Number}(x::Array{T, 1})
    y = Array(Float64, length(x));
    for k = 1:length(x)
        y[k] = x[k]^2;
    end
    return(y);
end

これは理にかなっているように思えますが、私のコードは、パラメトリック型を避けた場合と同じくらい速く実行されるでしょうか?

要約すると、私の質問には 2 つの部分があります。

  1. 高速なコードが重要な場合、上記のようにパラメトリック型を使用する必要がありますか?それとも、異なる具象型に対して複数のバージョンを作成する必要がありますか? それとも、まったく別のことをする必要がありますか?

  2. スカラーだけでなく配列も操作する関数が必要な場合、スカラー用と配列用の 2 つのバージョンの関数を作成することをお勧めしますか? それとも、まったく別のことをする必要がありますか?

最後に、上記のコードで考えられるその他の問題を指摘してください。ここでの私の最終的な目標は、優れた Julia コードを書くことです。

4

2 に答える 2

43

Julia は、必要に応じて入力セットごとに特定のバージョンの関数をコンパイルします。したがって、パート1に答えるには、パフォーマンスの違いはありません。パラメトリックな方法は、進むべき道です。

パート 2 については、場合によっては別のバージョンを作成することをお勧めします (たとえば、コピーを避けるなどのパフォーマンス上の理由から)。ただし、組み込みのマクロ@vectorize_1argを使用して、配列バージョンを自動的に生成できます。たとえば、次のようになります。

function mysquare{T<:Number}(x::T)
    return(x^2)
end
@vectorize_1arg Number mysquare
println(mysquare([1,2,3]))

一般的なスタイルに関しては、セミコロンを使用しないでくださいmysquare(x::Number) = x^2

ベクトル化された については、 が であるmysquare場合を考えてみましょう。ただし、出力配列は. これを処理する 1 つの方法は、次のように変更することです。TBigFloatFloat64

function mysquare{T<:Number}(x::Array{T,1})
    n = length(x)
    y = Array(T, n)
    for k = 1:n
        @inbounds y[k] = x[k]^2
    end
    return y
 end

ここで@inbounds、境界違反を毎回チェックする必要がないため、速度を上げるためにマクロを追加しました。長さはわかっています。この関数は、 の型x[k]^2が notである場合に問題が発生する可能性がありTます。さらに防御的なバージョンは、おそらく

function mysquare{T<:Number}(x::Array{T,1})
    n = length(x)
    y = Array(typeof(one(T)^2), n)
    for k = 1:n
        @inbounds y[k] = x[k]^2
    end
    return y
 end

どこでone(T)_ 1_ _ _ _ _ これらの考慮事項は、非常に堅牢なライブラリ コードを作成する場合にのみ重要です。本当にs または s に昇格できるものだけを扱う場合、それは問題ではありません。大変そうに見えますが、パワーはすごいです。いつでも Python のようなパフォーマンスに落ち着いて、すべての型情報を無視することができます。TInt1.0TFloat64Float64Float64

于 2014-07-29T18:53:39.613 に答える