我们如何从 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()
在 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()