2012-02-14 153 views
0

为什么在使用CUDA时,如果我执行一个大小为1百万的FFT,每次都会有不同的结果?同一数据上的FFT与CUDA每次都会给出不同的结果?

我的硬件有费米架构。

+0

这很有趣。你能发布一些代码来告诉我们你在做什么吗? – 2012-02-14 19:56:06

+2

很可能是因为你每次都在做某种微妙的变化。向我们展示一个展示此问题的最小示例。 – Bart 2012-02-14 20:00:31

+0

除了发布一些代码,你需要更精确地描述“微妙不同”。 – 2012-02-14 20:07:02

回答

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)。我的输出如下:

[[email protected] directory]# gcc add.c -o add 
[[email protected] 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。

+1

这将如何解释从运行到运行在相同输入数据上的变化,其他要求硬件随机地重新排序运行的执行?根据我的经验,虽然执行顺序不能事先确定,但硬件不会随机化相同代码的执行顺序。 – talonmies 2012-02-14 21:09:08

+1

@talonmies我的印象并不是CUDA保证您将从运行到运行获得相同的执行顺序。虽然它可能不会(有意)随机化执行,但可能会受到某种干扰或某种干扰。如果CUDA确实提供了这样的保证,那么我会同意这个答案是不正确的,并将删除它。 – Patrick87 2012-02-14 21:21:42

+2

可能每次发布第一个发布的块到不同的多处理器,并且如果跨多处理器的块数量不均匀,那么执行顺序可能会在运行之间略有不同。如果涉及到原子,并且内存地址在不同运行中有所不同,则可能会更多地改变执行顺序。 BTW @ Patrick87,为了让您对浮点执行方差的解释真正正确,您可能想指出所有这一切的真正原因是“浮点算术是非关联性的”。 – harrism 2012-02-15 00:17:13

相关问题