为什么在使用 CUDA 时,如果我执行大小为 100 万的 FFT,每次得到的结果都会略有不同?
我的硬件采用费米架构。
最佳答案
这可能有一个简单的答案。 CUDA 程序经常使用 float 变量类型,因为它比 double 快得多。计算运算的顺序会显着影响浮点计算的最终值;这不是 CUDA 独有的,但您可能会特别敏锐地注意到这种影响,因为它是一个如此大规模的并行范例(并且并行性带来了不确定性,至少在进行全局归约之类的事情时是这样)。
编辑:需要说明的是,CUDA 不保证同一个内核将在多次执行中以相同的顺序执行,这是一个必要(但不充分)的条件。如果 CUDA 确实保证了这一点,那么执行算术运算的顺序就不可能在每次运行时发生变化,因此,人们不会期望看到相同浮点计算的不同值。
这是一个简单的 C 程序,证明了上述声明。试试代码
#include <stdio.h>
int main()
{
float a = 100.0f, b = 0.00001f, c = 0.00001f;
printf("a + b + c = %f\n", a + b + c);
printf("b + c + a = %f\n", b + c + a);
printf("a + b + c == b + c + a ? %d\n", (a + b + c) == (b + c + a));
return 0;
}
在 Linux 上,看看你得到了什么(我使用的是 64 位 RHEL 6 和 gcc 版本 4.4.4-13)。我的输出如下:
[user@host directory]# gcc add.c -o add
[user@host directory]# ./add
a + b + c = 100.000015
b + c + a = 100.000023
a + b + c == b + c + a ? 0
编辑:请注意,虽然这个程序可能暗示潜在的问题是浮点加法是不可交换的,但实际上浮点加法是非关联的(因为 C 从左到是的,恰好第一次加法执行为 (a + b) + c,第二次加法执行为 (b + c) + a)。非关联性的原因是浮点表示法只能表示有限多个有效数字(以 2 为基数,但对以 10 为基数的系统的讨论本质上是等价的)。例如,如果只能表示三个有效数字,我们得到 (100 + 0.5) + 0.5 = 100 + 0.5 = 100,而 100 + (0.5 + 0.5) = 100 + 1 = 101。在第一种情况下,中间值结果 100 + 0.5 必须被截断(或可能向上舍入),因为不可能只用三个有效数字表示中间值 100.5。
这种现象有许多重要的含义;例如,通过按大小(指数)的递增顺序添加数字,您将获得更准确的答案。真正的收获是,除非以相同顺序执行计算,否则您不应期望结果相同,这可能很难保证在真实 GPU 上使用 CUDA。
关于c++ - 使用 CUDA 对相同数据进行 FFT 每次都会给出不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9283261/