取模、乘法和除法運算在CPU和GPU上的效率

問題:

    將整數n分解爲i和j,滿足下面關係:

n  =  j * idim + i

    其中idim爲常量。

    以下爲三種算法實現:
    1) i = n % idim,j = (n - i) / idim

    2) j = n * ridim,i = n - j * idim,其中ridim = 1.0f / idim,爲浮點數。

    3) i = n % idim,j = (n - i) * ridim,其中ridim = 1.0f / idim,爲浮點數。

 

CPU上的實現代碼如下:

  1. // 算法1  
  2. for(int ii, i = 0; i < size; i++)  
  3. {  
  4.     ii = N[i] % IDIM;  
  5.     I[i] = ii;  
  6.     J[i] = (N[i] - ii) / IDIM;  
  7. }  
  8.   
  9. // 算法2:R1 = 1.0f/IDIM  
  10. for(int i=0,j=0;i<size;i++)  
  11. {  
  12.     j = floor(N[i]*R1);  
  13.     I[i] = N[i] - j*IDIM;  
  14.     J[i] = j;  
  15. }  
  16.   
  17. // 算法3:R1 = 1.0f / IDIM  
  18. for(int i = 0, ii = 0; i < size; i++)  
  19. {  
  20.     ii = N[i] % IDIM;  
  21.     I[i] = ii;  
  22.     J[i] = (N[i] - ii) * R1;  
  23. }  

GPU上的實現代碼如下:

  1. // 算法1  
  2. __global__ void kernel1(int *N, int *I, int *J, int IDIM, int JDIM)  
  3. {  
  4.     int tid = blockIdx.x * blockDim.x + threadIdx.x;  
  5.     if(tid < IDIM * JDIM)  
  6.     {  
  7.         int n = N[tid];  
  8.         int i = n % IDIM;  
  9.         I[tid] = i;  
  10.         J[tid] = (n - i) / IDIM;  
  11.     }  
  12. }  
  13.   
  14. // 算法2:R1 = 1.0f/IDIM  
  15. __global__ void kernel2(int *N, int *I, int *J, int IDIM, int JDIM)  
  16. {  
  17.     int tid = blockIdx.x * blockDim.x + threadIdx.x;  
  18.     int n, j;  
  19.     if(tid < IDIM * JDIM)  
  20.     {  
  21.         n = N[tid];  
  22.         j = floor(n*R1);  
  23.         I[tid] = n - j * IDIM;  
  24.         J[tid] = j;  
  25.     }  
  26. }  
  27.   
  28. // 算法3:R1 = 1.0f / IDIM  
  29. __global__ void kernel3(int *N, int *I, int *J, int IDIM, int JDIM, float R1)  
  30. {  
  31.     int tid = blockIdx.x * blockDim.x + threadIdx.x;  
  32.     if(tid < IDIM * JDIM)  
  33.     {  
  34.         int n = N[tid];  
  35.         int i = n % IDIM;  
  36.         I[tid] = i;  
  37.         J[tid] = (n - i) * R1;  
  38.     }  
  39. }  

計算效率如下:

N = 1000000, IDIM = 1000, JDIM = 1000

Core2 Q6600:

    算法1:  17 ms

    算法2:  34 ms

    算法3:  16 ms

GTX280:

    算法1:   0.36 ms

    算法2:   0.14 ms

    算法3:   0.23 ms

CUDA Visual Profiler的檢測結果顯示: 算法1的指令數高達98xxx,而算法2指令數僅爲29xxx,算法3的指令數爲65xxx。整數除法再一次應驗了手冊上的那句話:

Integer division and modulo operation are particularly costly and should be avoided...

但是好像取模運算並沒有想象中的那麼慢。

 

結論:

對於CPU,最好採用取模運算,整數除法和單精度乘法的效率差不多。

對於GPU,採用浮點運算最快,其次是取模運算,整數除法最慢。


http://www.cnblogs.com/codezhang/archive/2009/06/19/1506532.html 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章