You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CUDA统计1-N素数总数异常问题求助

问题分析与修复

错误根源

你的代码在size≥9时结果错误,直接原因是浮点数精度问题:使用floor(pow(number, 0.5))计算平方根时,对于完全平方数(如9),pow可能返回略小于实际整数平方根的值(例如2.999999999而非3.0),导致floor后得到比正确值小1的结果。这会让循环提前终止,漏掉对平方根本身的检查,使得完全平方数被错误地判定为素数。

修复方案

1. 修正素数判断逻辑

用整数运算替代浮点数计算,直接通过i*i <= number判断是否需要继续循环,彻底避免浮点数精度问题:

for (int i = 2; i * i <= number; i++) {
    if (number % i == 0)
        return;
}

2. 优化线程/块配置

原代码每个线程对应一个块的配置效率极低,且无法支持超大size(如1e7)。改用256线程/块的标准配置,计算所需块数为(size + 255) / 256(向上取整),确保覆盖所有数字。

3. 移除不必要的数组

无需预先分配并拷贝数组到设备,每个线程可直接通过全局索引计算对应的数字idx + 1,大幅节省内存和数据传输开销。

修正后的完整代码

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <cstdio>

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(int size, int* count) {
    // 计算全局线程索引
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    // 跳过超出size的线程(因块数向上取整)
    if (idx >= size)
        return;
    int number = idx + 1; // 对应数字1~size

    if (number <= 1)
        return;
    // 用整数运算判断素数,避免浮点数误差
    for (int i = 2; i * i <= number; i++) {
        if (number % i == 0)
            return;
    }
    // 原子操作累加素数计数
    atomicAdd(count, 1);
}

int main() {
    const int size = 10000000; // 可修改为任意size,包括1e7
    int host_primeCount = 0;
    int* dev_primeCount;

    HANDLE_ERROR(cudaSetDevice(0));
    HANDLE_ERROR(cudaMalloc((void**)&dev_primeCount, sizeof(int)));
    HANDLE_ERROR(cudaMemcpy(dev_primeCount, &host_primeCount, sizeof(int), cudaMemcpyHostToDevice));

    // 配置线程块:256线程/块,计算所需块数
    const int block_size = 256;
    int grid_size = (size + block_size - 1) / block_size;
    countPrimeGPU<<<grid_size, block_size>>>(size, dev_primeCount);

    HANDLE_ERROR(cudaGetLastError());
    HANDLE_ERROR(cudaDeviceSynchronize());

    HANDLE_ERROR(cudaMemcpy(&host_primeCount, dev_primeCount, sizeof(int), cudaMemcpyDeviceToHost));
    printf("Prime count for the first %d numbers: %d\n", size, host_primeCount);

    cudaFree(dev_primeCount);
    HANDLE_ERROR(cudaDeviceReset());
    return 0;
}

进一步优化建议

对于超大size(如1e7),全局原子操作atomicAdd会成为性能瓶颈。可以通过块级共享内存先统计每个块内的素数数量,再将块结果原子累加到全局计数,减少原子操作的次数,大幅提升性能。

内容的提问来源于stack exchange,提问作者Tracer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 15:45:19