CUDA块维度小于1024时部分逐元素矩阵乘法计算出错的原因是什么
问题根因:网格维度计算逻辑错误
你的问题核心出在网格尺寸的计算写法存在逻辑漏洞:ceil<int>(COLS / threads.x) 中COLS和threads.x都是整数类型,会先执行整数除法直接截断小数部分,后续的ceil操作完全没有生效,导致实际创建的网格小于需要覆盖的矩阵范围,边缘区域的元素没有对应线程做计算,保持了显存初始化的0值,所以出现结果错误。
验证匹配你的测试数据
我们可以直接对应你给出的测试结果验证这个结论:
- 块维度8×8时:15000刚好可以被8整除,整数除法结果和正确向上取整的结果一致,所以没有错误
- 块维度16×16时:15000/16的整数除法结果为937,实际需要向上取整到938,相当于x方向少了1个块(对应少8列)、y方向少了1个块(对应少8行),总错误元素数为
15000*8 + 14992*8 = 239936,和你的测试结果完全一致 - 块维度32×32时:15000/32的整数除法结果为468,实际需要向上取整到469,x方向少24列、y方向少24行,总错误元素数为
15000*24 + 14976*24 = 719424,和你的测试结果完全匹配 - 矩阵尺寸10000×10000时:10000可以被16整除,用16×16块时无错;如果用32×32块时你测试无错,本质还是网格计算的写法不严谨导致的兼容性问题。
修复方案
直接用整数向上取整的通用公式替换现有网格计算逻辑,完全避免浮点数运算和ceil的误用问题:
dim3 blocks( (COLS + threads.x - 1) / threads.x, (ROWS + threads.y - 1) / threads.y );
你现有核函数里的边界判断if (col < A.width && row < A.height)是正确的,多出的网格线程会被自动过滤,不会出现越界访问问题,替换后所有场景下的计算结果都会恢复正常。
内容的提问来源于stack exchange,提问作者Vinc37
相关产品推荐
相关产品推荐

