arrays - 处理多种类型和数组时如何编写 "good"Julia代码(多重分派(dispatch))

标签 arrays types julia multiple-dispatch

操作更新:请注意,在最新版本的 Julia (v0.5) 中,回答此问题的惯用方法是定义 mysquare(x::Number) = x^2 。使用自动广播覆盖矢量化案例,即 x = randn(5) ; mysquare.(x) 。另请参阅更详细地解释点语法的新答案。

我是 Julia 的新手,考虑到我的 Matlab 出身,我在确定如何编写利用多重分派(dispatch)和 Julia 类型系统的“良好”Julia 代码时遇到了一些困难。

考虑这样一种情况,我有一个函数提供 Float64 的平方。我可能会写成:

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

有时,我想对所有 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

但现在我有时会使用Int64 ,所以我又写了两个利用多重分派(dispatch)的函数:

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

这感觉很合理,但是我的代码运行速度会像我避免参数类型的情况一样快吗?

总而言之,我的问题分为两个部分:

  1. 如果快速代码对我很重要,我应该使用如上所述的参数类型,还是应该为不同的具体类型编写多个版本?或者我应该完全做点别的事情?

  2. 当我想要一个既可以操作数组又可以操作标量的函数时,编写该函数的两个版本(一个用于标量,一个用于数组)是否是一种好的做法?或者我应该完全做点别的事情?

最后,请指出您在上面的代码中可以想到的任何其他问题,因为我的最终目标是编写优秀的 Julia 代码。

最佳答案

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,请考虑 TBigFloat 的情况。但是,您的输出数组是 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

我添加了 @inbounds 宏来提高速度,因为我们不需要每次都检查绑定(bind)违规 - 我们知道长度。如果 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

其中,如果 TInt,则 one(T) 将给出 1,并且 1.0 如果 TFloat64,依此类推。仅当您想要制作超健壮的库代码时,这些考虑因素才重要。如果您确实只处理 Float64 或可以升级为 Float64 的事物,那么这不是问题。看似辛苦,但威力却惊人。您始终可以满足于类似 Python 的性能,而忽略所有类型信息。

关于arrays - 处理多种类型和数组时如何编写 "good"Julia代码(多重分派(dispatch)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25009072/

相关文章:

types - 向下转换 Rust 特征组合

optimization - 是否可以创建或访问间隙历史记录

arrays - 创建一个随机真/假数组

data-structures - Julia 中的元组与静态向量

mysql - SQL NOW() 给出 0000-00-00 00 :00:00

arrays - 将数组中的每一项乘以另一个数组中的每一项

arrays - 模式匹配算法

javascript - 每次单击按钮时推送和弹出值

c - 数组指针两种声明类型的差异

c - 什么是无符号数据类型?