cuda计算的结果在不断变化

cuda计算的结果在不断变化,cuda,Cuda,对不起我的英语。我有一个cuda内核,它会不时返回不同的结果值。这个内核计算序列和。我的内核由4个代码部分组成。让我解释一下这个内核是如何工作的。第一部分在线程()之间分配迭代。第二个代码部分显示每个线程如何计算半和。在第二部分之后,我们必须放置_syncthreads(),因为在第二部分之后,我们开始使用共享内存。在第三部分中,我将得到块中所有线程的结果之和,并将其放入threadIdx.x等于0的线程。在第四部分中,我得到所有线程块的结果和,并将其放入dSum[0] 我是否正确放置了\uu

对不起我的英语。我有一个cuda内核,它会不时返回不同的结果值。这个内核计算序列和。我的内核由4个代码部分组成。让我解释一下这个内核是如何工作的。第一部分在线程()之间分配迭代。第二个代码部分显示每个线程如何计算半和。在第二部分之后,我们必须放置_syncthreads(),因为在第二部分之后,我们开始使用共享内存。在第三部分中,我将得到块中所有线程的结果之和,并将其放入threadIdx.x等于0的线程。在第四部分中,我得到所有线程块的结果和,并将其放入dSum[0]

我是否正确放置了\uu syncthreads()?哪里有错误?为什么在64个块和768个线程上给出错误的结果,而在768个块和64个线程上给出正确的结果

__global__ void sumSeries(double* dSum,int totalThreadNumber){  
    volatile  __shared__ double data[768];  
    int tid=threadIdx.x+blockIdx.x*blockDim.x;
    int myend;
    double var;
    //part_1 get tid's start iteration value and end iteration value.
    int mystart = (INT_MAX / totalThreadNumber) * tid;
    if (INT_MAX %  totalThreadNumber > tid)
    {
        mystart += tid;
        myend = mystart + (INT_MAX /  totalThreadNumber) + 1;
    }
    else
    {
        mystart += INT_MAX %  totalThreadNumber;
        myend = mystart + (INT_MAX /  totalThreadNumber);
    }
    //part_2 get halfsum
    data[threadIdx.x]=0;
    for (int i = mystart ; i < myend ; ++i){
            var=i;
            data[threadIdx.x] += (var*var+var+1)/(var*var*var+var*var+var+1);

    }   
    __syncthreads();

    //part_3 sum all results in every block
    for (int s=blockDim.x/2; s>32; s>>=1)
    {
        if (threadIdx.x < s)
            data[threadIdx.x] += data[threadIdx.x + s];
        __syncthreads();
    }
    if (threadIdx.x < 32)
    {
        data[threadIdx.x] += data[threadIdx.x + 32];
        data[threadIdx.x] += data[threadIdx.x + 16];
        data[threadIdx.x] += data[threadIdx.x + 8];
        data[threadIdx.x] += data[threadIdx.x + 4];
        data[threadIdx.x] += data[threadIdx.x + 2];
        data[threadIdx.x] += data[threadIdx.x + 1];
    }

    if (threadIdx.x==0)
    {
        dSum[blockIdx.x]=data[0];
    }
    __syncthreads();
    //part_4
    if (tid==0)
        for (int t=1;t<8;++t)
            dSum[0]=dSum[0]+dSum[t];
}
\uuuuu全局\uuuuuvoid sumSeries(双*dSum,int totalThreadNumber){
易失性共享双数据[768];
int tid=threadIdx.x+blockIdx.x*blockDim.x;
内梅恩德;
双重var;
//part_1获取tid的开始迭代值和结束迭代值。
int mystart=(int_MAX/totalThreadNumber)*tid;
如果(整数最大值%totalThreadNumber>tid)
{
mystart+=tid;
myend=mystart+(INT_MAX/totalThreadNumber)+1;
}
其他的
{
mystart+=INT_MAX%totalThreadNumber;
myend=mystart+(INT_MAX/totalThreadNumber);
}
//第2部分得到半和
数据[threadIdx.x]=0;
for(int i=mystart;i32;s>>=1)
{
如果(螺纹内径x.x对于(int t=1;t,那么你的和就是上面的级数

(n^2+n+1)/(n^3+n^2+n+1) = (n^3-1)/(n^4-1)
1/n
这与上面的调和级数具有相同的收敛性

(n^2+n+1)/(n^3+n^2+n+1) = (n^3-1)/(n^4-1)
1/n
从1到N的和的值介于log(N)和1-log(2)+log(N+1)之间

关于求和的顺序,这些级数的任何有限求和的结果都是非常合理的。从1到N的正向求和和和递减将抑制1==1+1/N的所有项,这发生在一个相当小的浮点数上。从一些N到1的反向求和将首先累加小数,并保留它们的累积值贡品

因此,根据部分和的到达顺序,特别是当包含1的和进来时,总和将显示出明显的差异


这两项都是单调递减的

f(x) = (x^2+x+1)/(x^3+x^2+x+1) = 0.5/(x+1)+0.5*(x+1)/(x^2+1)
这个函数的反导数是

F(n) = 0.5*ln(x+1)+0.25*ln(x^2+1)+0.5*arctan(x)
所以

f(n+1) <= F(n+1)-F(n) <= f(n) <= F(n)-F(n-1)

是从0到2^32-1的总和的上限和下限,与任何数值结果都相去甚远。

我理解。我认为结果必须是相同的,因为在每次cuda启动时,0线程将从0到349525计数元素,第二个线程将从349526计数到…他们以一种方式求和的每次启动..我启动了mpi模拟在192个线程上。它返回了与sequel Anague相同的结果。你能解释为什么在64个块和768个线程上它给出了错误的结果,而在768个块和64个线程上它给出了正确的结果吗?据我所知,线程将并行运行。你控制线程结果到达的顺序吗?你是否在它们到达时汇总结果或者它们存储到最后一个到达,然后求和?最好是从最后一个到第一个。它在代码中,对所有人都是这样。求和也会从后面到前面漂移,所以应该没有可以避免的浮点对消。我对并行计算的理解还不够好,看不出会出什么问题。卢兹尔,我认为这是错的你是正确的..当我将块数从1或2(总和=21.7276)个线程块增加到1024(总和=16.1234)-8128(总和=14.8549)我看到序列和变得越来越低。你是认真的吗?你在做什么?当你用
cuda memcheck
运行你的代码时会发生什么?你运行的是什么类型的GPU,你的
nvcc
编译命令行是什么?