2012-04-04 5 views
3

Ich weiß, dass OpenCL keine Unterstützung für komplexe Zahlen bietet, und nach dem, was ich gelesen habe, wird diese Funktion nicht so bald auftauchen. Einige Beispiele verwenden jedoch komplexe Zahlen in OpenCL-Kerneln (z. B. FFT-Implementierungen).Unterstützung für komplexe Zahlen in OpenCL

Hat jemand Erfahrung damit? Was wäre die "beste" Methode, um die Unterstützung komplexer Zahlen in OpenCL zu aktivieren? Ich würde annehmen, ein float2 zu verwenden, um die realen und imaginären Teile zu enthalten, aber sollte ich eine Reihe von Makros schreiben, oder sind Inline-Funktionen besser? Weiß jemand, ob zu diesem Zweck bereits eine Reihe von Funktionen/Makros existiert?

+0

der Artikel hier i llustrates, wie man es macht: http://developer.amd.com/resources/documentation-articles/articles-whitepapers/opencl-optimization-case-study-fast-fourier-transform-part-1/ – ChrisF

Antwort

6

Also, wie ich eine Reihe von Funktionen benötigt, um komplexe Zahlen in OpenCL zu behandeln, habe ich eine Reihe von ihnen implementiert. Insbesondere benötigte ich Summe und Subtraktion (trivial, kann mit Standardvektoroperationen durchgeführt werden), Multiplikation, Division, Erhalten eines Komplexes Modulus, Argument (oder Winkel) und Quadratwurzel.
relevant wikipedia Artikel:
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
Diese meist trivial, aber es einige Zeit dauert, so in der Hoffnung, in jemand diese Zeit sparen könnte, hier geht:

//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

Dieser Ein-Buchstabe ' #define Ich werde dich eines Tages hart beißen ;-). – rubenvb

+0

@rubenvb warum ist das? Hast du ein Beispiel? –

+1

Sie können das carg (cfloat a) durch die Funktion atan2 ersetzen, die bereits in OpenCL implementiert ist: https://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/atan.html – Dirklinux

4

PyOpenCL a hat etwas vollständigere und robuste Implementierung von komplexen Zahlen in OpenCL:

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

+0

Guter Tipp, danke :) Aus Ihrem Repository "Beachten Sie, dass Addition (real + complex) und Multiplikation (complex * complex) definiert sind, aber zu falschen Ergebnissen führen". Was meinst du damit? reelle + komplexe Addition wurde tatsächlich nicht definiert und komplex * komplexe Multiplikation wird zu 'Rückkehr (TP) expandieren (a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); } 'Was sieht mir gut aus oder gibt es etwas, das ich übersehe? –

+0

Link-Update: https://github.com/pyopencl/pyopencl/blob/master/pyopencl/cl/pyopencl-complex.h – tesch1