【问题标题】:Numerical Error in simple CUDA code简单 CUDA 代码中的数值错误
【发布时间】:2025-12-19 23:25:12
【问题描述】:

我刚开始用以下 cude 试验 cuda

#include "macro.hpp"
#include <algorithm>
#include <iostream>
#include <cstdlib>

//#define double float
//#define double int

int RandomNumber(){return static_cast<double>(rand() % 1000);}

__global__ void sum3(double const* a,
             double const* b,
             double const* c,
             double * result, 
             unsigned const* n)
{    
   unsigned i = blockIdx.x;
   while(i < (*n))
{
  result[i] = (a[i] + b[i] + c[i]);
}
};


int main()
{

  static unsigned size = 1e2;
  srand(0);
  double* a = new double[size];
  double* b = new double[size];
  double* c = new double[size];
  double* result = new double[size];

  std::generate(a, a+size, RandomNumber);
  std::generate(b, b+size, RandomNumber);
  std::generate(c, c+size, RandomNumber);

  double* ad, *bd,* cd;
  double* resultd;

  unsigned * sized;
  std::cout << cudaMalloc((void**) &ad, size*sizeof(double)) << std::endl;
  std::cout << cudaMalloc((void**) &bd, size*sizeof(double)) << std::endl;
  std::cout << cudaMalloc((void**) &cd, size*sizeof(double)) << std::endl;
  std::cout << cudaMalloc((void**) &resultd, size*sizeof(double)) << std::endl;
  std::cout << cudaMalloc((void**) &sized, sizeof(unsigned)) << std::endl;

  cudaMemcpy((void**) &sized, &size, sizeof(unsigned), cudaMemcpyHostToDevice);

  //  print_array(a, size);
  for(int i = 0; i < 1000; ++i)
    {
      cudaMemcpy(ad, a, size*sizeof(double), cudaMemcpyHostToDevice);
      cudaMemcpy(bd, b, size*sizeof(double), cudaMemcpyHostToDevice);
      cudaMemcpy(cd, c, size*sizeof(double), cudaMemcpyHostToDevice);      
      sum3<<<size, 1>>>(ad, bd, cd, resultd, sized);
      cudaMemcpy(result, resultd, size*sizeof(double), cudaMemcpyDeviceToHost);
    }

#ifdef PRINT
  for( int i = 0; i < size; ++i)
    {
      std::cout << a[i] << ", "<< b[i] <<"," << c[i] << "," << result[i]<< std::endl;
    }
#endif

  cudaFree(ad);
  cudaFree(bd);
  cudaFree(cd);
  cudaFree(resultd);

  delete[] a;
  delete[] b;
  delete[] c;
  delete[] result;

  return 0;
}

在 mac book pro 上编译没有任何问题。但是,当我尝试运行它时,我得到了

930, 22,538,899
691, 832,205,23
415, 655,148,120
872, 876,481,985
761, 909,583,619
841, 104,466,917
610, 635,911,52
//more useless numbers

我已经将我的样本与 Cuda By Example 中的样本进行了比较,除了类型之外我没有发现任何重大差异。对此问题的任何指针表示赞赏。

【问题讨论】:

  • 你希望这条线做什么? std::generate(a, a+size, RandomNumber);它会认为 a+size 是错误的,因为将数组指针添加到数字通常是错误的,因为您将超过数组的末尾。
  • doesnt *(a+size) 在元素 a[size-1] 之后给出地址空间吗?
  • @James:越过数组很好,也很常见。 @leon:你的指针算术很好。尽管您确实需要使用受范围限制的资源管理概念(也称为 RAII)。对于动态数组,总是使用std::vector。而且您可能也应该将 CUDA 内存包装到一个容器中。如果你处于不得不释放某些东西的位置,那你就做错了。它应该自动发生。
  • @Gman 在理想情况下,上面的所有代码都应该是直接的 C 代码,将 Malloc()Free。我正在使用new,因为它在原型中比malloc() 少几个字符:)
  • @leon:我不确定我是否跟上了。您使用std::vector,它更安全、更容易。使用它你会失去什么?对一些内存进行基本的包装需要 2 分钟。

标签: c++ c cuda gpu numerical


【解决方案1】:
while(i < (*n))
{
  result[i] = (a[i] + b[i] + c[i]);
}

错了(无限)

这是错误的

cudaMemcpy((void**) &sized, &size, sizeof(unsigned), cudaMemcpyHostToDevice);

&amp;sized是指针变量的地址,不是指针值

可以将单个数字传递给堆栈上的设备,因此请使用

unsigned size

检查你的 cuda 函数的返回状态,http://www.drdobbs.com/high-performance-computing/207603131

【讨论】:

  • @leon。抱歉,我之前误解了您的代码,请参阅我的更新
  • 我刚刚意识到它应该是 if 而不是 while :)
【解决方案2】:

你写道:

double* a = new double[size];

所以,“a”是一个指向双精度数组的指针,那么你说

  std::generate(a, a+size, RandomNumber);
  std::generate(b, b+size, RandomNumber);
  std::generate(c, c+size, RandomNumber);

错了,你应该说

  std::generate(*a, (*a)+size, RandomNumber);
  std::generate(*b, (*b)+size, RandomNumber);
  std::generate(*c, (*c)+size, RandomNumber);

如果你说明你想让你的程序做什么,会更容易帮助你。

还有,你把

 unsigned * sized;
 std::cout << cudaMalloc((void**) &ad, size*sizeof(double)) << std::endl;

但你可以这样做

 unsigned * sized;
 std::cout << cudaMalloc((void*) ad, size*sizeof(double)) << std::endl;

取决于你想要做什么。

【讨论】:

  • 在 C/C++ 中,a[] 中的名称 a 是指向数组第一个元素的指针,而不是指向双精度数组。其次,std::generate 采用指向范围开头的指针(迭代器)和范围中最后一个元素之后的内存地址。 (*a)+size = a[0]+size 对于 generate 参数没有意义。最后,cudaMalloc() 接受指针的指针,所以我传递了&amp;ad(void**) &amp;ad(void*)ad 不同。 *&amp;adad 相同,但这不是我正在做的。