我正在写一个CUDA内核,我一直在遇到一些奇怪的行为,整数除法和常数让我挠头。
我将说明下面发生的事情:
#define X 8
#define Y 4
#define K X/Y
...code....
int var = 8;
...code....
printf("K = %d, var = %d, var/K = %d\n", K, var, var/K);
我在一个循环中使用var / K作为终止条件,我怀疑var / K会给出一个值4,但它的值为1,从而破坏了我的内核。这是print语句的输出:
K = 2, var = 8, var/K = 1
当我将K从#define更改为int:
类型的全局常量时__device__ const int K=X/Y;
问题消失了,除法结果给出了4,我的内核正常运行。我已经尝试将K转换为int(这不应该是必要的)并且不会改变任何内容。
我想知道在划分常数方面是否有一些限制,或者我是否在某处有一个基本的误解。
答案 0 :(得分:3)
这里的基本问题与CUDA无关;它将表现为普通的C / C ++编译器。
如评论中所示,以这两种不同的方式创建“常量”:
#define K X/Y
和
const int K=X/Y;
正如您所发现的,在所有情况下都不会产生相同的效果。第一种方法使用C或C ++ 预处理器来遍历您的代码,并在X/Y
找到K
的任何位置进行文字(文本)替换。所以当你这样做时:
int var = 8;
printf("K = %d, var = %d, var/K = %d\n", K, var, var/K);
在语言处理开始之前,表达式var/K
完全被var/X/Y
替换。由于C和C ++会从左到右评估这样的表达式,因此它不会产生您期望的结果。
第二种方法当然会在语言中创建一个真正的变量,并按预期工作。同样,这些都不是CUDA独有的。
虽然它可能无法消除所有类型的古怪行为,但在使用涉及表达式的预处理器宏(即#define
)时,常见的建议是始终在这些宏周围使用括号,如下所示:
#define K (X/Y)
这通常会强制通过语言处理器以与您的意图一致的方式评估宏中的文本表达式。特别是,它可以防止您在此处产生的不必要的副作用,其中宏的某些部分在宏本身中的表达式被评估之前参与相邻的操作。当然,简单地定义全局const
变量就像您已经发现的那样,并且可能是更好的选择。
顺便说一句,并且在评论中再次提及,我希望var/K
如你所示,在你所给出的情况下被评估为0而不是1。但是你没有显示完整的代码,因此这里可能还有其他工作,而且无论意见如何,你所使用的宏的使用都不会给你8/2 = 4的预期结果。因此,无论它是0,如我所声称,还是1,如你所声称的那样,它不会给出你预期的4的结果。