如何声明可以有int和float的数组类型

时间:2016-09-07 23:06:55

标签: julia

我是朱莉娅的新手,仍然想弄清楚一切。 我想将输入变量类型限制为可以包含int和float的数组。 我真的很感激任何帮助。

function foo(array::??)

2 个答案:

答案 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])

更新了Julia 0.6 +

中的语法
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}foo2foo1相比无法提供更多的加速,因为优化inner_foo的好处会受到动态调度成本的影响。

foo3要快得多(~7次),如果可能的类型有限且提前知道(如上例中元素为Int64或Float64),则可以使用

有关进一步的讨论,请参阅https://groups.google.com/forum/#!topic/julia-users/OBs0fmNmjCU