c++ - OpenCL 内核浮点除法给出不同的结果

标签 c++ c floating-point opencl gpu

我有一个 OpenCL 内核用于一些计算。我发现只有一个线程使用 CPU 代码给出不同的结果。我使用的是vs2010 x64 Release模式。

通过一些示例检查 OpenCL 代码,我发现了一些有趣的结果。以下是内核代码中的测试示例。

我在OpenCl内核中测试了3种情况,精度通过printf("%.10f", fval);检查

情况1:

float fval = (10296184.0) / (float)(x*y*z);  // which gives result fval = 3351.6225585938

float fval = (10296184.0f) / (float)(x*y*z);  // which gives result fval = 3351.6225585938

变量是:int x,y, z

这些值是通过一些操作计算出来的。它们的值为 x=12, y=16, z=16;

情况2:

float fval = (10296184.0) / (float)(12*16*16); // which gives result fval = 3351.6223144531

float fval = (10296184.0f) / (float)(12*16*16); // which gives result fval = 3351.6223144531

情况3:

但是,当我计算 fval 的差异时使用以上两个表达式,如果使用10296184.0,结果为0 .

float fval = (10296184.0) / (float)(x*y*z) - (10296184.0) / (float)(12*16*16); // which gives result fval = 0.0000000000

float fval = (10296184.0f) / (float)(x*y*z) - (10296184.0f) / (float)(12*16*16); // which gives result fval = 0.0001812663

谁能解释一下原因或者给我一些提示吗?

最佳答案

一些观察:

两个 float 值相差 1 ULP 。因此结果存在最小程度的差异。

// Float ULP in the 2's place here
//       v
0x1.a2f3ea0000000p+11 3351.622314... // OP's lower float value 
0x1.a2f3eaaaaaaabp+11 3351.622395... // higher precision quotient
0x1.a2f3ec0000000p+11 3351.622558... // OP's higher float value 

(10296184.0)/(float)(12*16*16)编译时计算,结果更接近预期的数学答案。

float fval = (10296184.0)/(float)(x*y*z)运行时计算。

考虑到使用的是 float 变量,令人惊讶的是代码使用 double 数学进行除法运算。这是一个 double 常量除以 double(这是 float 产品的升级),结果是 double > 商,转换为 float 然后保存。我希望使用 10296184.0f - 请注意 f - ,然后数学就可以全部作为 float 完成。

C 允许由 FLT_ROUNDS 表示的不同舍入模式,这在编译时和运行时可能有所不同,并且可能解释了差异。了解 fegetround() 的结果(该函数获取当前舍入方向。)会有所帮助。

OP可能采用了各种牺牲精度来换取速度的编译器优化。

<小时/>

C 不指定数学运算的精度,但在高质量平台上,*/+ - sqrt() modf() 应该能达到最后的 ULP 效果。我怀疑代码的数学实现较弱。

关于c++ - OpenCL 内核浮点除法给出不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39025822/

相关文章:

c++ - 如何在 g++ 中抑制 ' left shift count >= width of type' 警告

c++ - 为什么 void_t<> 检测习语不适用于 gcc-4.9?

opencv - 使用opencv保存或读取float和double值到yaml文件时更改值

c++ - 为什么我们得到构建错误 "error C2065: ' ostringstream' : undeclared identifier"& How to fix this?

创建输入文件大小未知的数组

c++ - 按值传递参数和按引用传递参数有什么区别?

c - 根据时间执行函数

java - 为什么 0.1 正确地表示为 float ? (我知道为什么不是 2.0-1.9 的结果)

将 IEEE754 转换为自定义浮点表示形式

C++有效比较整数序列(按相对顺序)