我怎样才能加速这个Julia代码?

dog*_*ood 4 performance number-theory julia

该代码实现了一个Pollard rho()函数的示例,用于查找正整数n的因子.我已经检查了Julia"Primes"包中的一些代码,这些代码快速运行以试图加速pollard_rho()函数,但都无济于事.代码应该在大约100毫秒到30秒(Erlang,Haskell,Mercury,SWI Prolog)中执行n = 1524157897241274137,但在JuliaBox,IJulia和Julia REPL上需要大约3到4分钟.我怎样才能让它变得快速?

pollard_rho(1524157897241274137)= 1234567891

__precompile__()
module Pollard

export pollard_rho

function pollard_rho{T<:Integer}(n::T)
    f(x::T, r::T, n) = rem(((x ^ T(2)) + r), n)
    r::T = 7; x::T = 2; y::T = 11; y1::T = 11; z::T = 1
    while z == 1
        x  = f(x, r, n)
        y1 = f(y, r, n)
        y  = f(y1, r, n)
        z  = gcd(n, abs(x - y))
    end
    z >= n ? "error" : z
end

end # module
Run Code Online (Sandbox Code Playgroud)

Fen*_*ang 12

这里的类型不稳定存在很多问题.

  1. 不要返回字符串"error"或结果; 而是显式调用error().

  2. 正如克里斯提到,x并且r应该被注解为类型T,否则,他们将是不稳定的.

溢出似乎也存在潜在问题.一种解决方案是在截断回到类型之前在平方步骤中加宽T.

function pollard_rho{T<:Integer}(n::T)
    f(x::T, r::T, n) = rem(Base.widemul(x, x) + r, n) % T
    r::T = 7; x::T = 2; y::T = 11; y1::T = 11; z::T = 1
    while z == 1
        x  = f(x, r, n)
        y1 = f(y, r, n)
        y  = f(y1, r, n)
        z  = gcd(n, abs(x - y))
    end
    z >= n ? error() : z
end
Run Code Online (Sandbox Code Playgroud)

进行这些更改后,该功能将以您预期的速度运行.

julia> @btime pollard_rho(1524157897241274137)
  4.128 ms (0 allocations: 0 bytes)
1234567891
Run Code Online (Sandbox Code Playgroud)

要查找类型不稳定的这些问题,请使用@code_warntype宏.

  • 没有`widemul`你溢出`Int64`并且算法错误地重复179216149次.正确的计算只迭代16752次. (5认同)