2017-08-07 22 views
0

問題があります。私はOpenClを学ぼうとしているので、OpenClでFFTアルゴリズムを実装しようとしています。私はこれを再作成しようとしていた:OpenClアルゴリズムの実装結果が異なります

void FFT (cmplx* data, int dataSize){ 
    if(dataSize == 1){ 
     return; 
    }else{ 
     cmplx* even = (cmplx*)malloc(dataSize/2*sizeof(cmplx)); 
     cmplx* odd = (cmplx*)malloc(dataSize/2*sizeof(cmplx)); 
     for (int i = 0;i<dataSize;i+=2){ 
      even[i/2] = data[i]; 
      odd[i/2] = data[i+1]; 
     } 

     FFT(even,dataSize/2); 
     FFT(odd,dataSize/2); 

     for (int i = 0;i<dataSize;i++){ 
      cmplx C = cmplx(-2*M_PI/dataSize*i); 
      data[i].real = even[i].real + C.real*odd[i].real - C.imag*odd[i].imag; 
      data[i].imag = even[i].imag + C.real*odd[i].imag + C.imag*odd[i].real; 
     } 
    } 
} 

CMPLXがちょうど複素数の2つのfloat実部と虚部を保持し、オイラー方程式で複素数を作成するコンストラクタを持つクラスです。他のすべては、私はおそらくいくつかの小さなニュアンスが分からない、非常にまっすぐ進む

である私の理解で私はこのようなサイクルので、独立したスレッドでは、サイクルの計算を行うことができます。このようなOpenCLのコードで

for (int i = 0;i<dataSize;i++){ 
    cmplx C = cmplx(-2*M_PI/dataSize*i); 
    data[i].real = even[i].real + C.real*odd[i].real - C.imag*odd[i].imag; 
    data[i].imag = even[i].imag + C.real*odd[i].imag + C.imag*odd[i].real; 
} 

__kernel void FFTComplexSum(__global float *evenReal,__global float *evenImag, 
         __global float *oddReal,__global float *oddImag, 
         __global float *real,__global float *imag, 
         __global float *C){ 
    int gid = get_global_id(0); 
    real[gid] = evenReal[gid] + cos(C[gid])*oddReal[gid] - sin(C[gid])*oddImag[gid]; 
    imag[gid] = evenImag[gid] + cos(C[gid])*oddImag[gid] + sin(C[gid])*oddReal[gid]; 
} 

しかし、この実行する場合:

.... // instantiating stuff like platform, device_id, kernel, program... 
    size_t buffer_size; 
    cl_mem evenReal_mem, evenImag_mem, oddReal_mem, oddImag_mem, real_mem, imag_mem, c_mem; 

    float evenReal[dataSize]; 
    float evenImag[dataSize]; 
    float tReal[dataSize]; 
    float tImag[dataSize]; 
    float oddReal[dataSize]; 
    float oddImag[dataSize]; 
    float C[dataSize]; 

    for (int i = 0;i<dataSize;i+=2){ 
     evenReal[i/2] = real[i]; 
     evenImag[i/2] = imag[i]; 
     oddReal[i/2] = real[i+1]; 
     oddImag[i/2] = imag[i+1]; 
     C[i] = -2*M_PI/dataSize*i; 
     C[i+1] = -2*M_PI/dataSize*(i+1); 
    } 

    doubleArray(evenReal,dataSize); // doubleArray function just makes array to loop 
    doubleArray(evenImag,dataSize); 

    doubleArray(oddReal,dataSize); 
    doubleArray(oddImag,dataSize); 

    buffer_size = sizeof(float) * dataSize; 

    evenReal_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, evenReal_mem, CL_TRUE, 0, buffer_size,(void*)evenReal, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    evenImag_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, evenImag_mem, CL_TRUE, 0, buffer_size,(void*)evenImag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    oddReal_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, oddReal_mem, CL_TRUE, 0, buffer_size,(void*)oddReal, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    oddImag_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, oddImag_mem, CL_TRUE, 0, buffer_size,(void*)oddImag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    real_mem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, real_mem, CL_TRUE, 0, buffer_size,(void*)real, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    imag_mem = clCreateBuffer(context, CL_MEM_WRITE_ONLY, buffer_size, NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, imag_mem, CL_TRUE, 0, buffer_size,(void*)imag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    c_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float), NULL, NULL); 
    err = clEnqueueWriteBuffer(cmd_queue, c_mem, CL_TRUE, 0, sizeof(float),(void*)C, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); // Fail check 

    clFinish(cmd_queue); 

    err = clSetKernelArg(kernel[0], 0, sizeof(cl_mem), &evenReal_mem); 
    err = clSetKernelArg(kernel[0], 1, sizeof(cl_mem), &evenImag_mem); 
    err = clSetKernelArg(kernel[0], 2, sizeof(cl_mem), &oddReal_mem); 
    err = clSetKernelArg(kernel[0], 3, sizeof(cl_mem), &oddImag_mem); 
    err = clSetKernelArg(kernel[0], 4, sizeof(cl_mem), &real_mem); 
    err = clSetKernelArg(kernel[0], 5, sizeof(cl_mem), &imag_mem); 
    err = clSetKernelArg(kernel[0], 6, sizeof(cl_mem), &c_mem); 
    assert(err == CL_SUCCESS); // Fail check 

    size_t global_work_size = dataSize; 
    err = clEnqueueNDRangeKernel(cmd_queue, kernel[0], 1, NULL, &global_work_size, NULL, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); 
    clFinish(cmd_queue); 

    printf("test data:\n"); 

    for (int i = 0;i<dataSize;i++){ 
     float r,I; 
     r = evenReal[i] + cos(C[i])*oddReal[i] - sin(C[i])*oddImag[i]; 
     I = evenImag[i] + cos(C[i])*oddImag[i] + sin(C[i])*oddReal[i]; 
     printf("%f + %f\n",r,I); 
    } 

    err = clEnqueueReadBuffer(cmd_queue, real_mem, CL_TRUE, 0, buffer_size, tReal, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); 
    clFinish(cmd_queue); 
    err = clEnqueueReadBuffer(cmd_queue, imag_mem, CL_TRUE, 0, buffer_size, tImag, 0, NULL, NULL); 
    assert(err == CL_SUCCESS); 
    clFinish(cmd_queue); 

    clReleaseMemObject(evenReal_mem); 
    clReleaseMemObject(evenImag_mem); 
    clReleaseMemObject(oddReal_mem); 
    clReleaseMemObject(oddImag_mem); 
    clReleaseMemObject(real_mem); 
    clReleaseMemObject(imag_mem); 
    clReleaseMemObject(c_mem); 

    prinf("data:"); 

    for (int i = 0;i<dataSize;i++){ 
     printf("%f + %f\n",tReal[i],tImag[i]); 
    } 

それrを

test data: 
1.000000 + 0.000000 
0.000000 + 1.000000 
-1.000000 + 0.000000 
-0.000000 + -1.000000 
data: 
1.000000 + 0.000000 
-1.000000 + 0.000000 
1.000000 + 0.000000 
-1.000000 + 0.000000 

私は間違った答えを得るのは本当に混乱しています。本当に明白な何かが欠けていますか?

申し訳ありませんが長い質問です。

答えて

0

c_memに問題があります。

Cにアクセスするには、C[gid]のように、カーネルではsizeof(float)のサイズで作成してください。したがって、メインデータはその(4バイト)のメモリ空間に収まらず、4バイトしか書き込めません。作成サイズと書き込みサイズの両方にdata_sizeを乗じるだけで十分です。

imaginariesがゼロ(sin(0))の間、実際の値が1と-1になる理由は何ですか?運があれば、Cがあふれてゴミが出て、実際の要素と虚偽の要素の両方にゴミの結果が与えられ、エラーの原因がすぐに表示されます。

+0

Omg ...私はこれを見ないために恥ずかしいと感じる...ありがとう。 –

関連する問題