[英]How to specify the type signature to find a specific method with InteractiveUtils.edit in Julia?
[英]How do I specify a function's type/signature in Julia?
我正在实现牛顿方法来在预编译的库中查找根 。 常见的情况是使用从Float64
到Float64
函数,我希望它的优化编译版本存在于库中。 当然,我也将实现类型的泛型版本,但是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
尚未使用/调试。 例如,我不检查导数是否为零,因为我为此编写的特殊情况不需要它。
请注意,如果将guess
, rtol
和abstol
参数指定为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提供了许多功能和设施来帮助您完成此任务,例如zero
, iszero
, similar
等等。
只需使用您的通用函数,它将具有与“专用”函数相同的性能。 在Julia中,针对特定类型的专用功能仅在您需要其他算法时才有意义。 例如, intersect(circle, triangle)
需要与intersect(circle, circle)
不同的代码。 但是,对于使用32位浮点数和使用64位浮点数的圆,您不会编写其他方法。
为了给出一些具体的建议,让我对您编写的一些代码发表评论。
if rtol <= 0.0
error("findrootNewton: rtol must be a positive number")
end
对于通用版本,最好按优先顺序编写以下版本之一:
if rtol <= zero(rtol)
if rtol <= zero(T)
,其中T
是rtol
的类型 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)
但是,对convert
和typeof
的调用没有任何区别。 在所有类型都匹配的理想情况下,这些调用会被优化掉。 看这个简单的例子:
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.