問題:
將整數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
- for(int ii, i = 0; i < size; i++)
- {
- ii = N[i] % IDIM;
- I[i] = ii;
- J[i] = (N[i] - ii) / IDIM;
- }
- // 算法2:R1 = 1.0f/IDIM
- for(int i=0,j=0;i<size;i++)
- {
- j = floor(N[i]*R1);
- I[i] = N[i] - j*IDIM;
- J[i] = j;
- }
- // 算法3:R1 = 1.0f / IDIM
- for(int i = 0, ii = 0; i < size; i++)
- {
- ii = N[i] % IDIM;
- I[i] = ii;
- J[i] = (N[i] - ii) * R1;
- }
GPU上的實現代碼如下:
- // 算法1
- __global__ void kernel1(int *N, int *I, int *J, int IDIM, int JDIM)
- {
- int tid = blockIdx.x * blockDim.x + threadIdx.x;
- if(tid < IDIM * JDIM)
- {
- int n = N[tid];
- int i = n % IDIM;
- I[tid] = i;
- J[tid] = (n - i) / IDIM;
- }
- }
- // 算法2:R1 = 1.0f/IDIM
- __global__ void kernel2(int *N, int *I, int *J, int IDIM, int JDIM)
- {
- int tid = blockIdx.x * blockDim.x + threadIdx.x;
- int n, j;
- if(tid < IDIM * JDIM)
- {
- n = N[tid];
- j = floor(n*R1);
- I[tid] = n - j * IDIM;
- J[tid] = j;
- }
- }
- // 算法3:R1 = 1.0f / IDIM
- __global__ void kernel3(int *N, int *I, int *J, int IDIM, int JDIM, float R1)
- {
- int tid = blockIdx.x * blockDim.x + threadIdx.x;
- if(tid < IDIM * JDIM)
- {
- int n = N[tid];
- int i = n % IDIM;
- I[tid] = i;
- J[tid] = (n - i) * R1;
- }
- }
計算效率如下:
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,採用浮點運算最快,其次是取模運算,整數除法最慢。