繁体   English   中英

如何在Julia中指定函数的类型/签名?

[英]How do I specify a function's type/signature in Julia?

我正在实现牛顿方法来在预编译的库中查找根 常见的情况是使用从Float64Float64函数,我希望它的优化编译版本存在于库中。 当然,我也将实现类型的泛型版本,但是Julia需要通过签名区分方法的某种方式,以便它知道在运行时调用哪个方法。 当前,实现为:

#Float64 optimized version
function findrootNewton( func, funcder, guess::Float64,
                        rtol::Float64=1e-12, abstol::Float64=1e-12, maxiter::Int=100 )
    #make sure tolerances are positive
    if rtol <= 0.0
        error("findrootNewton: rtol must be a positive number")
    end

    if abstol <= 0.0
        error("findrootNewton: abstol must be a positive number")
    end

    if maxiter <= 0.0
        error("findrootNewton: maxiter must be a positive integer")
    end

    converged::Bool = false

    oldx::Float64 = guess
    newx::Float64 = oldx - ((func(oldx) / funcder(oldx))::Float64)
    absdiff = abs(oldx - newx)

    iter = 2
    while (absdiff < abstol || absdiff < rtol * abs(newx)) && iter <= maxiter
        oldx = newx
        newx = oldx - func(oldx) / funcder(oldx)
        absdiff = abs(oldx - newx)

        iter += 1
    end #while (absdiff < abstol || absdiff < rtol * abs(newx)) && newxiter <= maxiter

    if iter <= maxiter
        converged = true
    end

    return (newx, converged)
end #findzeroNewton

#Generic version
function findrootNewton( func, funcder, guess::Number,
                        rtol::Real=1e-12, abstol::Real=1e-12, maxiter::Int=100 )
    #make sure tolerances are positive
    if rtol <= 0
        error("findrootNewton: rtol must be a positive number")
    end

    if abstol <= 0
        error("findrootNewton: abstol must be a positive number")
    end

    if maxiter <= 0
        error("findrootNewton: maxiter must be a positive integer")
    end

    converged::Bool = false

    newx = oldx - func(oldx) / funcder(oldx)
    oldx = convert(typeof(newx), guess)
    absdiff = abs(oldx - newx)

    iter = 2
    while (absdiff < abstol || absdiff < rtol * abs(newx)) && iter <= maxiter
        oldx = newx
        newx = oldx - func(oldx) / funcder(oldx)
        absdiff = abs(oldx - newx)

        iter += 1
    end #while (absdiff < abstol || absdiff < rtol * abs(newx)) && newxiter <= maxiter

    if iter <= maxiter
        converged = true
    end

    return (newx, converged)
end #findzeroNewton

尚未使用/调试。 例如,我不检查导数是否为零,因为我为此编写的特殊情况不需要它。

请注意,如果将guessrtolabstol参数指定为Float64 ,但函数不会返回Float64而是BigFloat ,则即使在newx的定义中,即使有方法,代码也会在类型断言时失败适用于可用的通用功能。 有办法避免这个问题吗?

编辑:我可以指定变量存储在Julia中的数据类型,例如:

x::Float64 = 2.5

是否可以类似地指定可以存储(指向)函数的变量的签名?

为了清楚起见,我将在评论中写我的评论:除非在函数体中实现专门的处理,否则无需在Julia中对类型的函数签名进行专门化。 参数类型断言对代码速度或可编译性没有影响。 参见http://docs.julialang.org/en/latest/manual/performance-tips/

julia中函数参数中的类型断言主要用于控制多个分派,即对于不同类型的输入参数,不同的函数行为。 当不声明类型时,编译器将为输入参数的每种组合自动编译类型专用的版本。

如果出于其他原因(例如,确保类型稳定性)需要断言函数的返回类型与输入相同,则可以执行

function foo(x::T)::T where T
...
end

这不是编写Julia代码的方法。 您正在编写Julia,就好像它是静态类型的语言一样。 这是一个容易犯的错误,因为Julia看起来很像静态类型的语言。 为了在Julia中获得性能,重要的不是使用类型注释,而是实现类型稳定性。

这意味着编写代码,以便在执行一段代码时,变量的类型不会改变。 Julia提供了许多功能和设施来帮助您完成此任务,例如zeroiszerosimilar等等。

只需使用您的通用函数,它将具有与“专用”函数相同的性能。 在Julia中,针对特定类型的专用功能仅在您需要其他算法时才有意义。 例如, intersect(circle, triangle)需要与intersect(circle, circle)不同的代码。 但是,对于使用32位浮点数和使用64位浮点数的圆,您不会编写其他方法。


为了给出一些具体的建议,让我对您编写的一些代码发表评论。

 if rtol <= 0.0
        error("findrootNewton: rtol must be a positive number")
 end

对于通用版本,最好按优先顺序编写以下版本之一:

  1. if rtol <= zero(rtol)
  2. if rtol <= zero(T) ,其中Trtol的类型
  3. if rtol <= 0

因为这样可以确保您比较的是相等类型的数目,从而避免了类型转换。 整数0优于浮点0.0因为它通常会导致较少的类型转换/促销。

仅仅为了nitpick,您可能想要使用throw(DomainError(rtol, "findrootNewton: rtol must be a positive number"))来指示函数参数之一在域之外。


例如,我可以指定变量存储在Julia中的数据类型

 x::Float64 = 2.5 

这是不必要的,并且是错误的思考方式。 请记住,Julia不是静态类型的语言。 如果您是C / C ++开发人员,则可以将变量视为大小不同的小内存盒,它们可以容纳浮点数,整数或布尔值。 然后,此分配意味着将2.5放入64位浮点数框中。

但是,这不是动态语言(如Julia)中发生的情况。 从概念上讲,您将创建一个浮点对象2.5并在其上粘贴标签x 分配方式与您所想的相反。 您没有将数字分配给名为x的框。 而是将标签x粘贴到数字2.5 所以写这样的东西:

converged::Bool = false

完全没有必要。 您不能确保将false放入布尔值大小的框中。 没有盒子。 取而代之的是,您将会converged的标签粘贴在一个false对象上,然后再声明converged的标签已附加到布尔对象上。 这不会给您带来性能或内存方面的优势。


您仅在常规版本中执行此行,并且可以假定与在Float64版本中相比,此性能较低。

oldx = convert(typeof(newx), guess)

但是,对converttypeof的调用没有任何区别。 在所有类型都匹配的理想情况下,这些调用会被优化掉。 看这个简单的例子:

julia> foobar(a, b) = convert(typeof(a), a + b)
foobar

julia> @code_warntype foobar(1, 1)
Body::Int64
1 ─ %1 = (Base.add_int)(a, b)::Int64
└──      return %1

julia> @code_warntype foobar(1.0, 1.0)
Body::Float64
1 ─ %1 = (Base.add_float)(a, b)::Float64
└──      return %1

您可以看到类型匹配时,Julia JIT会将其简化为简单的整数或浮点加法。

如果您不确定以一种方式编写函数对性能的影响,建议您习惯使用@code_warntype@code_llvm@code_native宏。 它们为您提供了有关Julia在给定特定参数集的情况下如何转换代码的宝贵信息。

至于您是否可以为函数签名创建类型断言的问题。 您目前无法在Julia中做到这一点。 在您的情况下,则不需要。

但是,解决方法通常涉及使用某些基于特征的方法。 您可以考虑将Newton方法的参数转换为类型,然后在其上分配输入。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM