我知道像“
Why you should never cast floats to ints”这样的文章以及许多其他人喜欢将一个浮点数转换为带符号的int是昂贵的.我也知道某些架构上的某些转换指令或SIMD向量指令可以加速该过程.我很好奇是否将整数转换为浮点也很昂贵,因为我在主题上找到的所有材料都只讨论了从浮点转换为整数的成本.
在有人说“你为什么不试试它?”之前我不是在谈论特定架构的性能,我对符合IEEE 754-2008标准的多个平台的转换算法行为感兴趣.转换算法中是否存在固有的影响性能?
直觉上,我认为从整数到浮点的转换通常会更容易,原因如下:
>只有当整数的精度超过二进制浮点数的精度时才需要舍入,例如, 32位整数到32位浮点数可能需要舍入,但32位整数到64位浮点数不会,32位整数也不会只使用24位精度.
>无需检查NAN或/ – INF或/ – 0.
>没有上溢或下溢的危险.
从int转换为float的原因是什么原因导致跨平台性能不佳(如果有的话)(除了在软件中模拟浮点数的平台)?从int到float的转换通常比float更便宜吗?
最佳答案 英特尔在其“架构优化参考手册”中指出,自Core2以来,CVTSI2SD在基本桌面/服务器线路上具有3-4个周期延迟(和1个周期吞吐量).这可以作为一个很好的例子.
从硬件的角度来看,这种转换需要一些帮助,使其适合合理的周期数量,否则,它会变得太昂贵.接下来是一个天真但相当好的解释.在所有考虑中,我假设单个CPU时钟周期足以进行全宽整数加法(但不会超长!),并且前一周期的所有结果都应用于周期边界.
具有适当硬件辅助的第一个时钟周期(priority encoder)在检测到两种特殊情况时给出了Count Leading Zeros(CLZ)结果:0和INT_MIN(MSB设置和所有其他位清除).最好单独处理0和INT_MIN(加载常量到目标寄存器并完成).否则,如果输入整数为负,则应否定;这通常需要一个周期(因为否定是反转和添加进位的组合).因此,花费了1-2个周期.
同时,它可以根据CLZ结果计算偏差指数预测.请注意,我们不需要处理非规范化值或无穷大. (我们能否根据CLZ(x)预测CLZ(-x),如果x <0?如果可以的话,这可以节省我们1个周期.) 然后,应用移位(再次使用1个周期,使用barrel shifter)以放置整数值,使其最高1位于固定位置(例如,使用标准3扩展位和24位尾数,这是位号26).桶形移位器的这种使用应将所有低位组合到粘性位(可能需要单独的自定义桶形移位器实例;但这比缓存兆字节或OoO dispatcher便宜).现在,最多3个周期.
然后,应用舍入.在我们的例子中,舍入分析4个最低电流值位(尾数LSB,保护,圆形和粘性),以及OTOH,当前舍入模式和目标符号(在周期1提取).舍入为零(RZ)导致忽略保护/圆/粘位.舍入为-∞(RMI)为正值,向∞(RPI)为负与零相同.舍入到相反符号的∞会导致在主尾数上加1.最后,舍入到最近关系到偶数(RNE):x000 … x011 – >丢弃; x101 … x111 – >加1; 0100 – >丢弃; 1100 – >添加1.如果硬件足够快以在同一周期添加此结果(我猜它很可能),我们现在最多有4个周期.
这个在前一步骤上的添加可以导致携带(如1111 – > 10000),因此,指数可以增加.最后一个循环是打包标志(从周期1开始),尾数(到“有效数字”)和偏差指数(从周期2计算得出CLZ结果,并可能用周期4的进位调整).所以,现在有5个周期.
Is conversion from int to float generally cheaper than float to int?
我们可以估算相同的转换,例如从binary32到int32(签名).假设NaN,INF或太大值的转换导致固定值,例如INT_MIN(-2147483648).在这种情况下:
拆分并分析输入值:S – 符号; BE偏向指数; M – 尾数(有效数字);也适用于舍入模式.如果:BE> = 158(这包括NaN和INF),则生成“不可转换”(溢出或无效)信号.如果BE <1,则产生“零”信号. 127(abs(x)< 1)和{RZ,或(x> 0和RMI),或(x <0和RPI)};或者,如果BE< 126(abs(x)<0.5)与RNE;或者,BE = 126,有效数= 0(没有隐藏位)和RNE.否则,可以针对以下情况生成针对最终1或-1的信号:BE< 127和:x< 0和RMI; x> 0和RPI; BE = 126和RNE.所有这些信号都可以在一个周期内使用布尔逻辑电路计算,并导致在第一个周期完成结果.并行且独立地,使用单独的加法器计算157-BE以在第2周期使用. 如果尚未最终确定,则我们具有abs(x)> = 1,因此,BE> = 127,但是BE <= 157(所以abs(x)<2 ** 31).从第1周期获得157-BE,这是需要的转移量.使用相同的桶形移位器应用此移位量,如int – >中所示.浮点算法,带有(再次)3个附加位和粘性位收集的值.这里花费了2个周期.
应用四舍五入(见上文).花费3个周期,并且可以生产携带物.在这里,我们可以再次检测整数溢出并产生相应的结果值.忘记额外的位,现在只值31位.
最后,如果x为负(sign = 1),则否定结果值.最多花费4个周期.
我不是一个经验丰富的二进制逻辑开发人员,所以可能会错过一些机会来压缩这个序列,但它看起来非常接近英特尔的价值观.因此,如果存在硬件辅助,转换本身会相当便宜(再说一遍,它导致不超过几千个门,因此对于当代芯片生产而言微不足道).
您还可以查看Berkeley Softfloat library – 它实现了几乎相同的方法,只需稍加修改即可.从ui32_to_f32.c源文件开始.它们为中间值使用更多的附加位,但这不是主要的.