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