我无法获得使用atomicMin
的正确语法。我想使用此函数对双精度而不是整数进行运算。
__global__ void npd(int *a, int *g)
{
int index = threadIdx.x;
__shared__ int d[N];
d[threadIdx.x]=a[index];
__syncthreads();
int dd;
int inn;
int u;
if( 0==threadIdx.x )
{
for( int u = 0; u<16; u++ )
{
atomicMin( g, d ) ;
}
}
}
答案 0 :(得分:1)
atomicMin
函数defined by CUDA不支持与浮点数一起使用。参考该文档,我们看到唯一可用的原型是int
,unsigned int
和unsigned long long int
(最后一个需要编译并在计算能力3.5或以下的GPU上运行)的原型。更高)。
至少有2个选项。
您可以重构代码以用classical parallel reduction替换原子。
如the programming guide中所述,可以使用atomicCAS
(比较并交换)加上某种循环来创建“任意”原子。
对于double
,这是一个可能的实现:
__device__ double atomicMin_double(double* address, double val)
{
unsigned long long int* address_as_ull = (unsigned long long int*) address;
unsigned long long int old = *address_as_ull, assumed;
do {
assumed = old;
old = atomicCAS(address_as_ull, assumed,
__double_as_longlong(fmin(val, __longlong_as_double(assumed))));
} while (assumed != old);
return __longlong_as_double(old);
}
This相关的问题和答案也可能很有趣,尽管它主要考虑了float
。
其他一些评论:
通过切换到float
而不是double
,我相信可以简化atomicMin
(或atomicMax
)操作,如我链接的答案所示以上,可能有一些警告(例如,没有NaN,INF数据)。我相信iee754 float
遵循两个量A
和B
的排序规则,使得如果A > B
,则*reinterpret_cast<int*>(&A) > *reinterpret_cast<int*>(&B)
。我不确定double
是否与long long
遵循类似的规则(可能会有其他人会说)。
在您的代码中,该循环可以首先对本地数量进行操作,然后最后进行一次原子操作,如下所示:
double v = *g;
for( int u = 0; u<16; u++ )
{
v = min(v,d);
}
atomicMin_double(g, v);
我认为应该更快