Col*_*ers 36 arrays types multiple-dispatch julia
我是朱莉娅的新手,鉴于我的Matlab起源,我在确定如何编写利用多个调度和Julia的类型系统的"好"Julia代码时遇到了一些困难.
考虑我有一个提供a的平方的函数的情况Float64
.我可以这样写:
function mysquare(x::Float64)
return(x^2);
end
Run Code Online (Sandbox Code Playgroud)
有时,我想Float64
在一维数组中对所有s 进行平方,但不想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
Run Code Online (Sandbox Code Playgroud)
但是现在我有时正在使用Int64
,所以我写了两个利用多个调度的函数:
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
Run Code Online (Sandbox Code Playgroud)
这是正确的吗?或者是否有更具思想性的方法来应对这种情况?我应该使用这样的类型参数吗?
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
Run Code Online (Sandbox Code Playgroud)
这感觉很合理,但我的代码运行速度会与避免参数类型的情况一样快吗?
总之,我的问题分为两部分:
如果快速代码对我很重要,我应该如上所述使用参数类型,还是应该为不同的具体类型写出多个版本?或者我应该完全做其他事情?
当我想要一个在数组和标量上运行的函数时,编写函数的两个版本是好的做法,一个用于标量,一个用于数组?或者我应该完全做其他事情?
最后,请指出您在上面的代码中可以想到的任何其他问题,因为我的最终目标是编写好的Julia代码.
OP更新:请注意,在最新版本的Julia(v0.5)中,回答这个问题的惯用方法是定义mysquare(x::Number) = x^2
.使用自动广播覆盖矢量化案例,即x = randn(5) ; mysquare.(x)
Iai*_*ing 42
Julia根据需要为每组输入编译函数的特定版本.因此,回答第1部分,没有性能差异.参数方式是要走的路.
至于第2部分,在某些情况下编写单独的版本可能是一个好主意(有时出于性能原因,例如,为了避免复制).但是,在您的情况下,您可以使用内置宏@vectorize_1arg
来自动生成阵列版本,例如:
function mysquare{T<:Number}(x::T)
return(x^2)
end
@vectorize_1arg Number mysquare
println(mysquare([1,2,3]))
Run Code Online (Sandbox Code Playgroud)
至于一般风格,不要使用分号,而且mysquare(x::Number) = x^2
要短得多.
至于你的矢量化mysquare
,考虑的情况T
是a BigFloat
.但是,你的输出数组是Float64
.处理此问题的一种方法是将其更改为
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
Run Code Online (Sandbox Code Playgroud)
我已经添加了@inbounds
宏以提高速度,因为我们不需要每次都检查绑定的违规 - 我们知道长度.如果类型x[k]^2
不是,则此功能仍可能存在问题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
Run Code Online (Sandbox Code Playgroud)
这里one(T)
会给1
如果T
是Int
,而且1.0
如果T
是一个Float64
,依此类推.这些注意事项只有在您想要创建超级健壮的库代码时才有意义.如果你真的只处理Float64
可以提升为Float64
s的s或者事物,那么这不是问题.这似乎很辛苦,但力量是惊人的.您总是可以满足于类似Python的性能并忽略所有类型信息.
从 Julia 0.6(大约 2017 年 6 月)开始,“点语法”提供了一种简单且惯用的方法来将函数应用于标量或数组。
您只需要提供以正常方式编写的函数的标量版本。
function mysquare{x::Number)
return(x^2)
end
Run Code Online (Sandbox Code Playgroud)
将 a 附加.
到函数名称(或将其预先添加到运算符)以在数组的每个元素上调用它:
x = [1 2 3 4]
x2 = mysquare(2) # 4
xs = mysquare.(x) # [1,4,9,16]
xs = mysquare.(x*x') # [1 4 9 16; 4 16 36 64; 9 36 81 144; 16 64 144 256]
y = x .+ 1 # [2 3 4 5]
Run Code Online (Sandbox Code Playgroud)
请注意,点调用将处理广播,如上一个示例所示。
如果在同一个表达式中有多个点调用,它们将被融合,以便y = sqrt.(sin.(x))
进行一次传递/分配,而不是创建一个包含 sin(x) 的临时表达式并将其转发到 sqrt() 函数。(这与 Matlab/Numpy/Octave/Python/R 不同,它们不做这样的保证)。
宏@.
向量化一行上的所有内容,因此@. y=sqrt(sin(x))
与y = sqrt.(sin.(x))
. 这对于多项式来说特别方便,因为重复的点可能会让人感到困惑......