我是朱莉娅的新手,仍然想弄清楚一切.我想将输入变量类型限制为可以包含int和float的数组.我真的很感激任何帮助.
function foo(array::??)
Run Code Online (Sandbox Code Playgroud)
Chr*_*kas 11
正如我在评论中提到的,出于性能原因,您不希望将它们混合使用.但是,如果您的数组可以是Floats或Ints,但是您不知道它将是哪个,那么最好的方法是使其在参数类型上进行调度:
function foo{T<:Number,N}(array::Array{T,N})
Run Code Online (Sandbox Code Playgroud)
这将使得编译为每个编号类型(仅在需要时)的阵列的单独的功能,并且由于用于编译器将是已知的类型,它将运行是否给它的功能的优化版本foo([0.1,0.3,0.4]),foo([1 2 3]),foo([1//2 3//4])等.
function foo(array::Array{T,N}) where {T<:Number,N}
Run Code Online (Sandbox Code Playgroud)
为了更加通用,您可以将其Array{Union{Int64,Float64},N}用作类型.这将允许Floats和Ints,你可以使用它的构造函数
arr = Array{Union{Int64,Float64},2}(4,4) # The 2 is the dimension, (4,4) is the size
Run Code Online (Sandbox Code Playgroud)
你可以通过这样做来调度这样的奇怪事情
function foo{T,N}(array::Array{T,N})
Run Code Online (Sandbox Code Playgroud)
即只是删除限制T.但是,由于编译器无法预先知道数组的任何元素是Int还是Float,因此无法很好地优化它.所以一般来说你不应该这样做......
但是,让我解释一下你可以使用这种方法,并且仍能获得具有良好性能的东西.它也适用于多次派遣.本质上,如果你使用一个严格类型化的调度函数调用来封装内部循环,那么在进行所有硬计算时,它可以确切地知道它是什么类型并且无论如何都要优化代码.最好用一个例子来解释.假设我们想做:
function foo{T,N}(array::Array{T,N})
for i in eachindex(array)
val = array[i]
# do algorithm X on val
end
end
Run Code Online (Sandbox Code Playgroud)
您可以使用不能编译为Int64或Float64的方法进行检查@code_warntype,val因为直到运行时它才会知道每个类型的类型i.如果检查@code_llvm(或@code_native为程序集),您会看到为了处理这个问题而生成了一个非常长的代码.我们可以做的是定义
function inner_foo{T<:Number}(val::T)
# Do algorithm X on val
end
Run Code Online (Sandbox Code Playgroud)
然后将foo定义为
function foo2{T,N}(array::Array{T,N})
for i in eachindex(array)
inner_foo(array[i])
end
end
Run Code Online (Sandbox Code Playgroud)
虽然这看起来和你一样,但它与编译器有很大的不同.请注意,inner_foo(array[i])为它看到的任何数字类型调度一个特殊编译的函数,所以在foo2算法X中有效地计算,并且唯一的无效部分是在inner_foo之上的包装(所以如果所有的时间都花在inner_foo上,那么你将获得基本上最大的表现).
这就是为什么Julia是围绕多次发送构建的:它是一种设计,允许您尽可能地推出优化功能.由于它,朱莉娅很快.用它.
小智 5
这应该是克里斯回答的评论,但我没有足够的评论.
正如Chris指出的那样,使用函数障碍对于生成最佳代码非常有用.但请注意,动态调度有一些开销.根据内部函数的复杂性,这可能重要也可能不重要.
function foo1{T,N}(array::Array{T,N})
s = 0.0
for i in eachindex(array)
val = array[i]
s += val*val
end
s
end
function foo2{T,N}(array::Array{T,N})
s = 0.0
for i in eachindex(array)
s += inner_foo(array[i])
end
s
end
function foo3{T,N}(array::Array{T,N})
s = 0.0
for i in eachindex(array)
val = array[i]
if isa(val, Float64)
s += inner_foo(val::Float64)
else
s += inner_foo(val::Int64)
end
end
s
end
function inner_foo{T<:Number}(val::T)
val*val
end
Run Code Online (Sandbox Code Playgroud)
因为A = Array{Union{Int64,Float64},N},优化的效益可以通过动态调度的成本来抵消,因此foo2不会提供太多的加速.foo1inner_foo
foo3 更快(~7次)并且可以使用,如果可能的类型是有限的并且提前知道(如上面的示例,其中元素是Int64或Float64)
有关进一步的讨论,请参阅https://groups.google.com/forum/#!topic/julia-users/OBs0fmNmjCU.