我正在为sigmoid内核寻找sigmoid函数和sigmoid素数实现,无意中在SO中发现了一个使用__fmul_rz
和其他一些CUDA函数名的回复。出于好奇,我在谷歌上搜索了一下,发现这些都是单精度函数,如下所示(注:这些是4.1的函数)
文件说这些是快速近似所以,直觉说它们跳过了精度,以便使计算更快?
以前我有:
float x = 1.f / (1.f + exp ( -1.f * input ) );
return x * ( 1.f - x );
而现在,我有:
float s = __fdividef( 1.f, (1.f + __expf(-1.f*input)));
return x = s * (1.f - s);
我认为上面的两个可能有不同的结果,这是对的吗?
我认为以上两种情况可能会产生不同的结果,这是对的吗?
你的假设是正确的。快速数学本质以性能换取精度和对某些特殊情况的处理。这取决于用户来决定这是否是一个可接受的折衷方案。
CUDA C编程指南,附录D.2。内部函数:
在这些函数中,有一些标准函数的精度较低但速度较快的版本。它们具有相同的名称,前缀为
__
(如__sinf(x)
)。它们的速度更快,因为它们映射到更少的本机指令。[…]除了降低受影响功能的准确性外,还可能导致特殊情况处理的一些差异。
文档还提供了一个实际的差异示例:
[…]对于2126<y<2128,
__fdividef(x,y)
传递的结果为零,而/
运算符传递的正确结果在表9中规定的精度范围内。对于2126<y<2128,如果x是无穷大,则__fdividef(x,y)
传递NaN
(作为无穷大乘以零的结果),而/
运算符返回无穷大。
对于__expf(x)
,最大ULP误差界被声明为2 + floor(abs(1.16 * x))
,而符合IEEE的expf
具有2的最大ULP错误界。