2016-05-17 3 views
0

pythonで素数を生成する最も速い方法は、C/C++ライブラリprimesievehttp://primesieve.org/)へのバインドであるprimesieve-pythonを使用することです。あなたは私たちがPyCallを使用してジュリアからこのPythonライブラリを呼び出すことができますJuliaからprimesieve Cライブラリをどのように呼び出すことができますか?

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

で素数を反復処理することができます。しかし、C関数primesieve_next_primeを直接呼び出すことで、素数を反復する方が早いことが予想されます。 Cを知らない人にとって、これは簡単にいかがですか?

+3

あなたはドキュメントのこの部分をたどる試みたことがありますか? http://docs.julialang.org/en/release-0.4/manual/calling-c-and-fortran-code/ – Chisholm

+0

これは私の最初のコールポートでした。しかし私は、例をhttp://primesieve.org/api/primesieve__iterator_8h.html#a4512ff6ce19e25042f07fe1337bb0dbeの定義に簡単に一致させることはできませんでした。私は、一般的なJuliaとは異なり、Cコードを呼び出すことは経験豊富なプログラマーにとってのみ重要な印象を与えました。 – u003f

+0

JuliaからC APIへのラッパーを作成するのはかなり簡単です。経験豊富なプログラマーだけではありません(C言語を実際に使用することさえできません。ほとんどの場合、同等のジュリアタイプがあります)。 C APIをラップするのにどの部分が問題をもたらしましたか? –

答えて

2

私は先に進み、それを包み、その例をJuliaに翻訳しました。 これはちょうど速かった&ダーティ(それは、より良いだろう、私はちょうどそれがC APIに一致させたジュリアのイテレータインターフェイスを使用しません) いくつかの点:C割り当てられたメモリが関与しているので、私はファイナライザを設定iteratorオブジェクトがスコープから外れてガベージコレクトされると、Cの割り当てられたメモリは解放されます。私はそれを明示的に解放できるようにしました(メモリを2回解放しようとするのを防ぐ)。 また、モジュールと各関数にはdoc文字列があります。私はそれが正しい結果だ願ってい

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

:それは私がそれを実行したとき、私は以下の結果を得たC.

に構造体へのポインタを渡すためにRefを使用しています!ここで

はちょうどIteratorインターフェイスの私の迅速なラッピングです:

""" 
    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() 
+0

これは優れており、Juliaの既存のプライム機能を実際に改善しています。 CライブラリのライセンスがJuliaパッケージとして使用されていることと一貫性があるのだろうか? – u003f

+0

私はあなたがそれを好きでうれしいです!ソースはBSD 2節でライセンスされています。これはMITライセンスとほとんど同じです。私はJuliaでCコードをラップするのは難しくないことを示す精神的な練習としてこれをやっただけです。私は数学者ではありません。 –

+0

良いニュース:あなたのコードは、次のベストプライムイテレータよりも20倍高速です(これは、奇妙なことですが、インクリメント 'n'の単純コードと' isprime(n) 'を実行)。 – u003f

関連する問題