为什么在使用CUDA时,如果我执行大小为100万的FFT,我每次都会得到一些微妙的不同结果?
我的硬件具有Fermi架构。
答案 0 :(得分:4)
这可能有一个简单的答案。 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。