在x86上将float转换为int的最快方法是什么

时间:2020-03-05 18:57:34  来源:igfitidea点击:

我们知道在x86 CPU上将浮点数转换为int的最快方法。对于以下任意组合,最好使用C或者汇编语言(可以在C语言中内联):

  • 32/64/80位浮点数-> 32/64位整数

我正在寻找一种比只让编译器来做更快的技术。

解决方案

回答

到目前为止,使用SSE进行压缩转换是最快的方法,因为我们可以在同一条指令中转换多个值。 ffmpeg为此有很多组件(主要是将音频的解码输出转换为整数样本);检查它的一些例子。

回答

汇编中有一条指令可将浮点转换为int:使用FISTP指令。它将值从浮点堆栈中弹出,将其转换为整数,然后存储在指定的地址处。我认为不会有更快的方法(除非我们使用我不熟悉的MMX或者SSE之类的扩展指令集)。

另一个指令FIST将值保留在FP堆栈上,但我不确定它是否适用于四字大小的目标。

回答

如果我们真的关心此速度,请确保编译器正在生成FIST指令。在MSVC中,我们可以使用/ QIfist执行此操作,请参阅此MSDN概述

我们也可以考虑使用SSE内在函数为我们完成工作,请参阅英特尔的这篇文章:http://softwarecommunity.intel.com/articles/eng/2076.htm

回答

这取决于我们要截断转换还是四舍五入以及转换的精度。默认情况下,当我们从float到int时,C将执行截断转换。有执行此操作的FPU指令,但这不是ANSI C转换,并且使用它时有很多警告(例如,了解FPU舍入状态)。由于问题的答案非常复杂,并且取决于我们尚未表达的一些变量,因此我建议就此问题发表本文:

http://www.stereopsis.com/FPU.html

回答

通常,我们可以相信编译器的效率和正确性。通常,通过为编译器中已经存在的内容滚动自己的函数不会获得任何收益。

回答

Lua代码库具有以下代码段(请从www.lua.org检入src / luaconf.h)。
如果我们找到(SO找到)更快的方法,我相信他们会很兴奋的。

哦," lua_Number"表示加倍。 :)

/*
@@ lua_number2int is a macro to convert lua_Number to int.
@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
** CHANGE them if you know a faster way to convert a lua_Number to
** int (with any rounding method and without throwing errors) in your
** system. In Pentium machines, a naive typecast from double to int
** in C is extremely slow, so any alternative is worth trying.
*/

/* On a Pentium, resort to a trick */
#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
    (defined(__i386) || defined (_M_IX86) || defined(__i386__))

/* On a Microsoft compiler, use assembler */
#if defined(_MSC_VER)

#define lua_number2int(i,d)   __asm fld d   __asm fistp i
#define lua_number2integer(i,n)     lua_number2int(i, n)

/* the next trick should work on any Pentium, but sometimes clashes
   with a DirectX idiosyncrasy */
#else

union luai_Cast { double l_d; long l_l; };
#define lua_number2int(i,d) \
  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
#define lua_number2integer(i,n)     lua_number2int(i, n)

#endif

/* this option always works, but may be slow */
#else
#define lua_number2int(i,d) ((i)=(int)(d))
#define lua_number2integer(i,d) ((i)=(lua_Integer)(d))

#endif

回答

普通x86 / x87代码的常用技巧是强制浮点数的尾数部分表示int。随后是32位版本。

64位版本是类比的。上面发布的Lua版本更快,但是依赖于将double截断为32位结果,因此它要求将x87单元设置为double precision,并且不能适应double到64位int转换。

此代码的优点是,它对于符合IEEE 754的所有平台都是完全可移植的,唯一的假设是浮点舍入模式设置为最接近。注意:就其编译和工作的意义而言,它是可移植的。 x86以外的平台通常根本无法从该技术中受益匪浅(如果有的话)。

static const float Snapper=3<<22;

union UFloatInt {
 int i;
 float f;
};

/** by Vlad Kaipetsky
portable assuming FP24 set to nearest rounding mode
efficient on x86 platform
*/
inline int toInt( float fval )
{
  Assert( fabs(fval)<=0x003fffff ); // only 23 bit values handled
  UFloatInt &fi = *(UFloatInt *)&fval;
  fi.f += Snapper;
  return ( (fi.i)&0x007fffff ) - 0x00400000;
}

回答

如果可以确保运行代码的CPU与SSE3兼容(即使奔腾5也为JBB),则可以允许编译器使用其FISTTP指令(即-msse3用于gcc)。它似乎在做应该总是应该做的事情:

http://software.intel.com/zh-CN/articles/how-to-implement-the-fisttp-streaming-simd-extensions-3-instruction/

请注意,FISTTP与FISTP不同(后者有问题,会导致运行缓慢)。它是SSE3的一部分,但实际上是(唯一的)X87方面的改进。

无论如何,其他X86 CPU可能都可以完成转换。 :)

具有SSE3支持的处理器