我们如何从朱莉娅那里打电话给primesieve C图书馆?

时间:2016-05-17 09:46:22

标签: c julia primes

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

迭代质数
import primesieve
it = primesieve.Iterator()
prime = it.next_prime()
prime = it.next_prime()

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

1 个答案:

答案 0 :(得分:2)

我继续把它包起来,把那个例子翻译成朱莉娅。 这只是快速和脏(它不使用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()