在调试一些 CUDA 代码时,我使用以下方法与等效的 CPU 代码进行比较printf
陈述,并注意到在某些情况下我的结果有所不同;它们在任何一个平台上都不一定是错误的,因为它们在浮点舍入误差之内,但我仍然有兴趣知道是什么导致了这种差异。
我能够将问题追溯到不同的点积结果。在 CUDA 和主机代码中,我都有向量 a 和 b 类型float4
。然后,在每个平台上,我使用以下代码计算点积并打印结果:
printf("a: %.24f\t%.24f\t%.24f\t%.24f\n",a.x,a.y,a.z,a.w);
printf("b: %.24f\t%.24f\t%.24f\t%.24f\n",b.x,b.y,b.z,b.w);
float dot_product = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
printf("a dot b: %.24f\n",dot_product);
CPU 的打印结果为:
a: 0.999629139900207519531250 -0.024383276700973510742188 -0.012127066962420940399170 0.013238593004643917083740
b: -0.001840781536884605884552 0.033134069293737411499023 0.988499701023101806640625 1.000000000000000000000000
a dot b: -0.001397025771439075469971
对于 CUDA 内核:
a: 0.999629139900207519531250 -0.024383276700973510742188 -0.012127066962420940399170 0.013238593004643917083740
b: -0.001840781536884605884552 0.033134069293737411499023 0.988499701023101806640625 1.000000000000000000000000
a dot b: -0.001397024840116500854492
正如您所看到的,a 和 b 的值在两个平台上似乎按位等效,但完全相同的代码的结果却略有不同。据我了解,浮点乘法是根据 IEEE 754 标准明确定义的,并且与硬件无关。然而,对于为什么我没有看到相同的结果,我确实有两个假设:
- 编译器优化是对乘法进行重新排序,它们在 GPU/CPU 上以不同的顺序发生,从而产生不同的结果。
- CUDA 内核使用融合乘加 (FMA) 运算符,如中所述http://developer.download.nvidia.com/assets/cuda/files/NVIDIA-CUDA-Floating-Point.pdf http://developer.download.nvidia.com/assets/cuda/files/NVIDIA-CUDA-Floating-Point.pdf。在这种情况下,CUDA 结果实际上应该更准确一些。