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

我们如何从Julia那里调用primesieve C库?,c,julia,primes,C,Julia,Primes,在python中生成素数的最快方法是使用primesieve-python,这是一个到C/C++库primesieve()的绑定。可以使用 import primesieve it = primesieve.Iterator() prime = it.next_prime() prime = it.next_prime() 我们可以使用PyCall从Julia调用这个python库。但是,我希望通过直接调用C函数primesife\u next\u prime来迭代素数会更快。对于不懂C语言的

在python中生成素数的最快方法是使用
primesieve-python
,这是一个到C/C++库
primesieve
()的绑定。可以使用

import primesieve
it = primesieve.Iterator()
prime = it.next_prime()
prime = it.next_prime()

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

我把它包装好,然后把这个例子翻译给Julia。 这太快了,太脏了(它没有使用Julia迭代器接口,这会更好,我只是让它与C API匹配) 几点:因为涉及到C分配的内存,所以我设置了一个终结器,这样,如果迭代器对象超出范围并被垃圾收集,C分配的内存仍然会被释放。我还这样做,它可以显式释放(并防止试图释放内存两次) 另外,模块和每个函数都有一个doc字符串(我也应该为类型加上)。它使用
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()
使用PrimeSieves
函数示例()
pit=PrimeSieveIterator()
总和=UInt64(0)
#迭代10^10以下的素数
而(prime=next(pit))
我继续打包,并将该示例翻译给Julia。 这太快了,太脏了(它没有使用Julia迭代器接口,这会更好,我只是让它与C API匹配) 几点:因为涉及到C分配的内存,所以我设置了一个终结器,这样,如果迭代器对象超出范围并被垃圾收集,C分配的内存仍然会被释放。我还这样做,它可以显式释放(并防止试图释放内存两次) 另外,模块和每个函数都有一个doc字符串(我也应该为类型加上)。它使用
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()
使用PrimeSieves
函数示例()
pit=PrimeSieveIterator()
总和=UInt64(0)
#迭代10^10以下的素数
而(prime=next(pit))
您是否尝试过遵循文档的这一部分?那是我的第一个停靠港。但是我不能轻易地将这些例子与当时的定义相匹配,我得到的印象是,与Julia不同,调用C代码只适合有经验的程序员。从Julia制作C API的包装器相当容易,而且不仅仅适合“有经验”的程序员(你甚至不知道C是否能够做到这一点,在大多数情况下,你只需要了解等价的Julia类型是什么)。包装C API的哪些部分给了你问题?示例是传递Julia内容(数字、字符串)这里我们需要设置一个C函数
primesieve\u迭代器
,在C中初始化它,然后在该C函数上运行C函数
primesieve\u next\u prime
,然后返回结果(一个数字)对Julia:看。你有没有试着按照文档的这一部分来做?那是我的第一个调用端口。但我当时无法轻松地将示例与定义匹配。我得到的印象是,与Julia不同的是,调用C代码只适合有经验的程序员。从Julia编写C API的包装器相当容易,而且不是仅针对“有经验”的程序员(你甚至不知道C是否能够做到这一点,在大多数情况下,你只需要了解等价的Julia类型是什么)。包装C API的哪些部分给了你问题?示例是传递Julia内容(数字、字符串)这里我们需要设置一个C函数
primesieve\u迭代器
,在C中初始化它,然后在该C函数上运行C函数
primesieve\u next\u prime
,然后返回结果(一个数字)给Julia:看。这很好,是对Julia中现有prime功能的真正改进。我想知道C库上的许可证是否与用作Julia包的许可证一致?我很高兴你喜欢它!源代码是根据BSD 2-clause授权的,它看起来几乎与MIT许可证相同。我只是作为一个心理练习来做的e为了说明在Julia中包装C代码并不难,我不是数学家。如果你认为它真的有用,我可以将它作为一个包添加(不过可能会包装其余的API!)好消息:你的代码比下一个最好的素数迭代器快20倍(奇怪的是,这是increment
n
和run
isprime(n)
)的简单代码。坏消息是:它遗漏了一些(尽管很少)素数,第一个是587(直接跳到593)。python(C++)
primesieve
的包装器不这样做,
primesieve
的命令行版本也不这样做。我不知道为什么会这样。底层C库也会这样做吗?好的,在重新加载primes缓冲区时,这一定是一个一次性的问题。我会尽快修复它。这非常好,是对现有prime的真正改进Julia中的功能。我想知道C库上的许可证是否与用作Julia软件包的许可证一致?我很高兴您喜欢它!源代码是根据BSD 2-clause获得许可的,它看起来几乎与MIT许可证相同。我只是做了一个心理练习,以帮助s