我是Cuda的新手。我正在尝试在内核中添加数组的float元素,但最终结果是错误的。因为我需要原子地做,但另一方面atomicAdd只用于整数...任何想法?
__global__ void add_element(float *my_array, float *result_sum){
int tid = blockIdx.x * blockDim.x + threadIdx.x;
*result_sum += my_array[tid];
}
int main(int argc, char** argv){
float my_array[10];
float result_sum = 0;
float *device_array, *device_sum;
cudaMalloc((void**)&device_array, 10*sizeof(float) );
cudaMalloc((void**)&device_sum, sizeof(float) );
// fill the array
for (int i=0; i<10; i++){
my_array[i] = (float)i/2;
}
cudaMemcpy(device_array, my_array, 10*sizeof(float),cudaMemcpyHostToDevice);
cudaMemcpy(device_sum, &result_sum, sizeof(float),cudaMemcpyHostToDevice);
add_element<<<1,10>>>(device_array, device_sum);
cudaMemcpy(&result_sum, device_sum, sizeof(float), cudaMemcpyDeviceToHost);
for(int i=0; i<10; i++){
printf(" %f \n", my_array[i]);
}
printf("+\n----------\n %f\n", result_sum);
cudaFree(device_array);
cudaFree(device_sum);
return 0;
}
答案 0 :(得分:1)
您也可以将atomicAdd用于float和double。 如下:
__device__ float atomicAdd(float *address, float val) { return 0; }
__device__ __forceinline__ float atomicAdd(float *address, float val)
{
// Doing it all as longlongs cuts one __longlong_as_double from the inner loop
unsigned int *ptr = (unsigned int *)address;
unsigned int old, newint, ret = *ptr;
do {
old = ret;
newint = __float_as_int(__int_as_float(old)+val);
} while((ret = atomicCAS(ptr, old, newint)) != old);
return __int_as_float(ret);
}
或 找到文件“derived_atomic_functions.h”并将您的项目添加为头文件。
答案 1 :(得分:0)
尝试使用此函数为浮点数执行AtomicAdd。
__device__ inline void atomicFloatAdd(float *address, float val)
{
int tmp0 = *address;
int i_val = __float_as_int(val + __int_as_float(tmp0));
int tmp1;
// compare and swap v = (old == tmp0) ? i_val : old;
// returns old
while( (tmp1 = atomicCAS((int *)address, tmp0, i_val)) != tmp0)
{
tmp0 = tmp1;
i_val = __float_as_int(val + __int_as_float(tmp1));
}
}
对于(capability&gt; 2.0),你有一个原生浮点atomicAdd(float * address,float val);
正如评论中所指出的,如果您想要更高效的实施,您可以使用并行缩减。 NVIDIA本身提供了一个有效的实现,可以找到here,并且可以找到有关实施的详细说明here