2012-04-04 22 views
3

OpenCLは複素数をサポートしていないことを知っています。この関数を読んだことで、すぐには表示されません。 しかし、いくつかの例では、OpenCLカーネル(たとえばFFT実装)で複素数を使用しています。OpenCLでの複素数のサポート

誰もこの経験がありますか? OpenCLで複素数サポートを有効にする「最良の」方法は何でしょうか?実数部と虚数部を格納するためにfloat2を使用すると仮定しますが、マクロのセットを書くべきか、インライン関数が良くなるのでしょうか?この目的のために関数/マクロのセットがすでに存在するかどうかは誰にも分かりますか?

+0

記事ここで私それを行う方法をllustrates:http://developer.amd.com/resources/documentation-articles/articles-whitepapers/opencl-optimization-case-study-fast-fourier-transform-part-1/ – ChrisF

答えて

6

OpenCLで複素数を処理する関数が必要になったので、私はそれらのセットを実装しました。具体的には、和と減算(簡単な、標準的なベクトル演算で行うことができます)、乗算、除算、複素数の係数、引数(または角度)と平方根の取得が必要でした。
関連するWikipediaの記事:
http://en.wikipedia.org/wiki/Complex_number#Absolute_value_and_argument
http://en.wikipedia.org/wiki/Square_root#Principal_square_root_of_a_complex_number
これは、ほとんど自明で、誰かにこの時間を節約するかもしれないで期待してて、それは、ある程度の時間がかかるん、ここに行く:

//2 component vector to hold the real and imaginary parts of a complex number: 
typedef float2 cfloat; 

#define I ((cfloat)(0.0, 1.0)) 


/* 
* Return Real (Imaginary) component of complex number: 
*/ 
inline float real(cfloat a){ 
    return a.x; 
} 
inline float imag(cfloat a){ 
    return a.y; 
} 

/* 
* Get the modulus of a complex number (its length): 
*/ 
inline float cmod(cfloat a){ 
    return (sqrt(a.x*a.x + a.y*a.y)); 
} 

/* 
* Get the argument of a complex number (its angle): 
* http://en.wikipedia.org/wiki/Complex_number#Absolute_value_and_argument 
*/ 
inline float carg(cfloat a){ 
    if(a.x > 0){ 
     return atan(a.y/a.x); 

    }else if(a.x < 0 && a.y >= 0){ 
     return atan(a.y/a.x) + M_PI; 

    }else if(a.x < 0 && a.y < 0){ 
     return atan(a.y/a.x) - M_PI; 

    }else if(a.x == 0 && a.y > 0){ 
     return M_PI/2; 

    }else if(a.x == 0 && a.y < 0){ 
     return -M_PI/2; 

    }else{ 
     return 0; 
    } 
} 

/* 
* Multiply two complex numbers: 
* 
* a = (aReal + I*aImag) 
* b = (bReal + I*bImag) 
* a * b = (aReal + I*aImag) * (bReal + I*bImag) 
*  = aReal*bReal +I*aReal*bImag +I*aImag*bReal +I^2*aImag*bImag 
*  = (aReal*bReal - aImag*bImag) + I*(aReal*bImag + aImag*bReal) 
*/ 
inline cfloat cmult(cfloat a, cfloat b){ 
    return (cfloat)(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x); 
} 


/* 
* Divide two complex numbers: 
* 
* aReal + I*aImag  (aReal + I*aImag) * (bReal - I*bImag) 
* ----------------- = --------------------------------------- 
* bReal + I*bImag  (bReal + I*bImag) * (bReal - I*bImag) 
* 
*  aReal*bReal - I*aReal*bImag + I*aImag*bReal - I^2*aImag*bImag 
*  = --------------------------------------------------------------- 
*   bReal^2 - I*bReal*bImag + I*bImag*bReal -I^2*bImag^2 
* 
*  aReal*bReal + aImag*bImag   aImag*bReal - Real*bImag 
*  = ---------------------------- + I* -------------------------- 
*   bReal^2 + bImag^2    bReal^2 + bImag^2 
* 
*/ 
inline cfloat cdiv(cfloat a, cfloat b){ 
    return (cfloat)((a.x*b.x + a.y*b.y)/(b.x*b.x + b.y*b.y), (a.y*b.x - a.x*b.y)/(b.x*b.x + b.y*b.y)); 
} 


/* 
* Square root of complex number. 
* Although a complex number has two square roots, numerically we will 
* only determine one of them -the principal square root, see wikipedia 
* for more info: 
* http://en.wikipedia.org/wiki/Square_root#Principal_square_root_of_a_complex_number 
*/ 
inline cfloat csqrt(cfloat a){ 
    return (cfloat)(sqrt(cmod(a)) * cos(carg(a)/2), sqrt(cmod(a)) * sin(carg(a)/2)); 
} 
+1

その1文字の ' #define私はいつかあなたを苦しめるつもりです;-)。 – rubenvb

+0

@rubenvbなぜですか?あなたは例がありますか? –

+1

carg(cfloat a)は、OpenCLで既に実装されているatan2関数で置き換えることができます。https://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/atan.html – Dirklinux

4

PyOpenCLが持っていますOpenCLの中複素数の多少より完全かつ堅牢な実装:

https://github.com/pyopencl/pyopencl/blob/master/pyopencl/cl/pyopencl-complex.h

+0

Guter Tip、danke :)あなたのリポジトリから "加算(実数+複素数)と乗算(複素数*複素数)は定義されていますが、間違った結果が得られます。これはどういう意味ですか?実数+複素数加算は実際には定義されておらず、複素数複素乗算は 'return(TP)(a.x * b.x - a.y * b.y、a.x * b.y + a.y * b.x)に拡張されます。 } '私にはうまく見える、または私が見落としているものがありますか? –

+0

リンクの更新:https://github.com/pyopencl/pyopencl/blob/master/pyopencl/cl/pyopencl-complex.h – tesch1

関連する問題