我们如何从 Julia 调用 primesieve C 库?

How can we call the primesieve C library from Julia?

在 python 中生成素数的最快方法是使用 primesieve-python,绑定到 C/C++ 库 primesieve (http://primesieve.org/) .您可以使用

遍历素数
import primesieve
it = primesieve.Iterator()
prime = it.next_prime()
prime = it.next_prime()

我们可以使用 PyCall 从 Julia 调用这个 python 库。但是,我希望通过直接调用 C 函数 primesieve_next_prime 来迭代素数会更快。对于不了解 C 语言的人来说,这有多容易?

我继续包装它,然后运行将这个例子交给了 Julia。 这只是快速和肮脏(它不使用 Julia 迭代器接口,这会更好,我只是让它匹配 C API) 几点:因为涉及到 C 分配的内存,我设置了一个终结器,这样如果迭代器对象超出范围并被垃圾收集,C 分配的内存仍然会被释放。我也做了它,以便它可以被显式释放(并防止尝试释放内存两次) 此外,模块和每个函数都有一个文档字符串(我也应该为类型加上)。它使用 Ref 将指向结构的指针传递给 C.

当我 运行 它时,我得到了以下结果:

julia> @time example()
Sum of the primes below 10^10 = 2220820311119164929
   5.836645 seconds (609 allocations: 16.324 KB)

我希望这是正确的结果!

这是我对迭代器接口的快速包装:

"""
    Wrapper for primesieves library
    Copyright 2016 Scott Paul Jones
    MIT Licensed
"""
module PrimeSieves

export PrimeSieveIterator, skipto, next, previous, free

const global psilib = "libprimesieve.dylib"

type PrimeSieveIterator
    i::Csize_t
    last_idx::Csize_t
    primes::Ptr{UInt64}
    primes_pimpl::Ptr{UInt64}
    start::UInt64
    stop::UInt64
    stop_hint::UInt64
    tiny_cache_size::UInt64
    is_error::Cint
    function PrimeSieveIterator()
        piter = new(0,0,C_NULL,C_NULL,0,0,0,0,0)
        ccall((:primesieve_init, psilib), Void, (Ref{PrimeSieveIterator},), piter)
        finalizer(piter, free)
        piter
    end
end

""" Free all memory """
function free(piter::PrimeSieveIterator)
    # Make sure it isn't freed twice
    if piter.primes != C_NULL
        ccall((:primesieve_free_iterator, psilib), Void, (Ref{PrimeSieveIterator},), piter)
        piter.primes = C_NULL
        piter.primes_pimpl = C_NULL
    end
    nothing
end
""" Set the primesieve iterator to start """
skipto(piter::PrimeSieveIterator, start::Integer, stop_hint::Integer) =
    ccall((:primesieve_skipto, psilib), Void,
          (Ref{PrimeSieveIterator}, UInt64, UInt64), piter, start, stop_hint)

""" Get the next prime """
function Base.next(piter::PrimeSieveIterator)
    (piter.i-1) >= piter.last_idx &&
        ccall((:primesieve_generate_next_primes, psilib), Void, (Ref{PrimeSieveIterator},), piter)
    unsafe_load(piter.primes, piter.i += 1)
end

""" Get the previous prime """
function previous(piter::PrimeSieveIterator)
    if piter.i == 0
        ccall((:primesieve_generate_previous_primes, psilib),
              Void, (Ref{PrimeSieveIterator},), piter)
    else
        piter.i -= 1
    end
    unsafe_load(piter.primes, piter.i + 1)
end

end

示例代码为:

using PrimeSieves

function example()
    pit = PrimeSieveIterator()
    sum = UInt64(0)
    # iterate over the primes below 10^10
    while (prime = next(pit)) < UInt64(10000000000)
        sum += prime
    end
    free(pit)
    println("Sum of the primes below 10^10 = ", sum)
end

example()