如果要模拟具有两个单精度浮点的双精度浮点,那么性能会是什么样的,并且可以做得好吗?
目前,Nvidia正在为双精度启用的特斯拉卡收取相当高的费用,使您能够获得单精度性能的三分之一(值得注意的是Titan / Titan Black除外)。
如果要使用具有gimped双精度的Geforce GPU并使用2个单精度浮点模拟双精度,性能会如何?
答案 0 :(得分:10)
通过计算实现每个双浮点运算所需的float
运算次数,可以粗略估计性能。您可能希望使用cuobjdump --dump-sass
检查二进制代码以获得准确的计数。我正在展示下面的双浮点乘法,它充分利用了GPU上的FMA(融合乘法 - 加法)支持。对于双浮点加法代码,我会指向a paper by Andrew Thall,因为我没有时间对此进行编码。根据之前的分析,我认为论文中给出的加法代码是正确的,并且它避免了更快但更不准确的实现中的常见缺陷(当操作数的大小在两倍之内时会失去准确性)。
如果您是注册的CUDA开发人员,您可以从NVIDIA的开发者网站(登录https://developer.nvidia.com)下载双倍代码,该代码具有BSD许可证,并且可以相对快速地将其重新编译为双浮动码。 NVIDIA的双重代码支持操作加法,减法,除法,平方根和倒数平方根。
如您所见,下面的乘法需要8 float
条指令;一元否定被FMA吸收。此添加需要大约20 float
条指令。但是,双浮点运算的指令序列也需要临时变量,这会增加寄存器压力并降低占用率。因此,合理保守的估计可能是双浮点运算在1/20的原始float
算术的吞吐量下执行。您可以在与您相关的上下文中(即您的用例)轻松地自行测量。
typedef float2 dblfloat; // .y = head, .x = tail
__host__ __device__ __forceinline__
dblfloat mul_dblfloat (dblfloat x, dblfloat y)
{
dblfloat t, z;
float sum;
t.y = x.y * y.y;
t.x = fmaf (x.y, y.y, -t.y);
t.x = fmaf (x.x, y.x, t.x);
t.x = fmaf (x.y, y.x, t.x);
t.x = fmaf (x.x, y.y, t.x);
/* normalize result */
sum = t.y + t.x;
z.x = (t.y - sum) + t.x;
z.y = sum;
return z;
}
请注意,在各种应用程序中,可能不需要完全双浮点运算。相反,可以使用float
计算,通过误差补偿技术进行增强,其中最古老的一种是Kahan summation。我在recent posting in the NVIDIA developer forums中简要概述了有关此类方法的简单文献。在上面的评论中,罗伯特克罗维拉也指出GTC 2015 talk by Scott LeGrand,我还没来得及退房。
至于精度,双浮点的表示精度为49(24 + 24 + 1)位,而IEEE-755 double
则提供53位。但是,对于操作数小的操作数,双浮点不能保持这种精度,因为尾部可以变为非正规或零。当打开非正规支持时,对于2 -101 < = | x |,保证49位精度。 < 2 128 。默认情况下,对于体系结构> = sm_20的CUDA工具链中启用了对float
的非正常支持,这意味着当前发布的版本CUDA 7.0支持所有体系结构。
与对IEEE-754 double
数据的操作相反,双浮动操作未正确舍入。对于上面的双浮点乘法,使用20亿随机测试用例(所有源操作数和结果在上述范围内),我观察到相对误差的上限为1.42e-14。我没有双浮点数的数据,但它的误差界限应该相似。