将浮点数组转换为整数的最佳方式.[替换x64的asm代码]



我有一个函数可以将浮点数组转换为无符号字符数组。这使用asm代码来实现。该代码是多年前编写的。现在我正在尝试用x64位构建解决方案。我知道X64不支持_asm。

删除asm依赖关系的最佳方法是什么?

如果我写C代码,最新的MS VC编译器会优化吗?有人知道实现这一点的助推或内在功能中是否有什么吗?

谢谢--Hari

我通过以下代码解决了问题,这比asm-更快

inline static void floatTOuchar(float * pInbuf, unsigned char *  pOutbuf, long len)
{
    std::copy(pInbuf, pInbuf + len, pOutbuf);
    return ;
}   

使用SSE2,可以使用内部函数从float压缩到unsigned char,饱和到无符号范围为0..255。

将浮点的四个向量转换为int的向量,使用CVTPS2DQ_mm_cvtps_epi32)四舍五入到最近值,或者如果您想要默认的C floor行为,则使用截断(_mm_cvttps_epi32)进行转换。

然后将这些向量打包在一起,首先打包到具有两个PACKSSDW_mm_packs_epi32)的有符号16位int的两个向量,然后打包到具有PACKUSWB_mm_packus_epi16)的无符号8位int的一个向量。请注意,PACKUSWB采用带符号的输入,因此使用SSE4.1 PACKUSDW作为第一步只会使事情变得更加困难(额外的屏蔽步骤)。int16_t可以表示uint8_t的所有可能值,所以没有问题。

存储uint8_t的结果向量,并对接下来的四个浮点向量重复此操作。


在没有手动矢量化的情况下,正常的编译器输出对类似代码来说是很好的。

int ftoi_truncate(float f) { return f; }
    cvttss2si       eax, xmm0
    ret
int dtoi(double d) { return nearbyint(d); }
    cvtsd2si        eax, xmm0   # only with -ffast-math, though.  Without, you get a function call :(
    ret

您可以尝试以下操作并告诉我:

inline int float2int( double d )
{
   union Cast
   {
      double d;
      long l;
    };
   volatile Cast c;
   c.d = d + 6755399441055744.0;
   return c.l;
}
// Same thing but it's not always optimizer safe
inline int float2int( double d )
{
   d += 6755399441055744.0;
   return reinterpret_cast<int&>(d);
}
for(int i = 0; i < HUGE_NUMBER; i++)
     int_array[i] = float2int(float_array[i]);

所以技巧是双重参数。在当前代码中,函数将浮点值四舍五入到最接近的整数。如果需要截断,请使用6755399441055743.5(少0.5)。

内容丰富的文章,可在以下网址获得:http://stereopsis.com/sree/fpu2006.html

最新更新