我刚开始使用CUDA,想使用Visual Studio编写一个简单的C++程序,该程序可以计算1-N中的素数总数。我这样做了:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cstdio>
#include <cmath>
static void HandleError(cudaError_t err,
const char* file,
int line) {
if (err != cudaSuccess) {
printf("%s in %s at line %d\n", cudaGetErrorString(err),
file, line);
exit(EXIT_FAILURE);
}
}
#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))
__global__ void countPrimeGPU(const int* array, int* count)
{
int number = array[threadIdx.x + blockIdx.x * blockDim.x];
if (number <= 1)
return;
for (int i = 2; i <= floor(pow(number, 0.5)); i++)
if (!(number % i))
return;
atomicAdd(count, 1);
}
int main()
{
int* host_array;
int* dev_array;
const int size = 9; // prime numbers from 1-9
// allocating & initializing host array
host_array = new int[size];
for (int i = 0; i < size; i++)
host_array[i] = i + 1; // 1, 2, ..., size
int host_primeCount = 0;
int* dev_pprimeCount;
HANDLE_ERROR(cudaSetDevice(0));
HANDLE_ERROR(cudaMalloc((void**)&dev_array, size * sizeof(int)));
HANDLE_ERROR(cudaMemcpy(dev_array, host_array, size * sizeof(int), cudaMemcpyHostToDevice));
HANDLE_ERROR(cudaMalloc((void**)&dev_pprimeCount, sizeof(int)));
HANDLE_ERROR(cudaMemcpy(dev_pprimeCount, &host_primeCount, sizeof(int), cudaMemcpyHostToDevice));
countPrimeGPU <<< size, 1 >>> (dev_array, dev_pprimeCount); // !!!
HANDLE_ERROR(cudaGetLastError());
HANDLE_ERROR(cudaDeviceSynchronize());
HANDLE_ERROR(cudaMemcpy(&host_primeCount, dev_pprimeCount, sizeof(int), cudaMemcpyDeviceToHost));
printf("Prime count for the first %d numbers: %d\n", size, host_primeCount);
cudaFree(dev_array);
cudaFree(dev_pprimeCount);
HANDLE_ERROR(cudaDeviceReset());
delete[] host_array;
return 0;
}
这里的问题是,只有当size
在[1-8]
区间内时,我才能得到正确的结果。但是,当将其设置为9
或更高时,它总是不正确。我做错了什么?我怀疑我设置的配置不正确(块/线程数),但无法修复。最后,我想用size=10'000'000
测试它,并与我的多线程CPU实现进行比较。谢谢。
1条答案
按热度按时间k5hmc34c1#
最接近的问题是当
number
为9时,floor(pow(number, 0.5))
给出的是2,而不是你所期望的3,结果9被错误地标记为素数。是一个类似的问题。(至少在CUDA设备代码中)在使用
floor()
时不具有您期望/需要的绝对精度(即截断)。使用普通舍入而不是截断,您可能会有一个可行的路径(因为对比平方根稍大的因子进行测试不会破坏方法的正确性),但我建议解决这个问题的方法是按如下方式更改for循环:这避免了浮点运算的麻烦,而且计算起来也更简单。对于你想要的
number
的范围(最多10,000,000),i*i
将适合int
类型/值,所以我不认为会有问题。由于这只是一个学习练习,我并不想对你的代码进行各种优化改进。举一个例子,启动每个线程的块:
在GPU上不是特别有效,但这样做在算法上并不错误。