c++ CUDA -从1到N的素数计数问题

tv6aics1  于 2022-12-05  发布在  其他
关注(0)|答案(1)|浏览(134)

我刚开始使用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实现进行比较。谢谢。

k5hmc34c

k5hmc34c1#

最接近的问题是当number为9时,floor(pow(number, 0.5))给出的是2,而不是你所期望的3,结果9被错误地标记为素数。
是一个类似的问题。(至少在CUDA设备代码中)在使用floor()时不具有您期望/需要的绝对精度(即截断)。使用普通舍入而不是截断,您可能会有一个可行的路径(因为对比平方根稍大的因子进行测试不会破坏方法的正确性),但我建议解决这个问题的方法是按如下方式更改for循环:

for (int i = 2; (i*i) <= number; i++)

这避免了浮点运算的麻烦,而且计算起来也更简单。对于你想要的number的范围(最多10,000,000),i*i将适合int类型/值,所以我不认为会有问题。
由于这只是一个学习练习,我并不想对你的代码进行各种优化改进。举一个例子,启动每个线程的块:

countPrimeGPU <<< size, 1 >>> (dev_array, dev_pprimeCount); // !!!

在GPU上不是特别有效,但这样做在算法上并不错误。

相关问题