什么是最快的方法你知道的把一个浮点数int在x86CPU。最好在C或组件(即,可以在排在C)对于任何组合如下:

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

我在找一些技术,这种技术是最快只是我们编译器这样做。

有帮助吗?

解决方案

这取决于如果你想要一个截断变换或四舍五入的一种以及在什么精确。通过默认,C将执行一个截断变换的时候你从浮到int。有FPU说明这样做,但这不是一个ANSI C的转换,存在着很大的注意事项以使用(诸如知道FPU四舍五入状态)。因为回答你的问题是相当复杂的,取决于一些变量没有表示,我建议本条的问题:

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

其他提示

包装的转换使用SSE是迄今为止最快的方法,因为你可以转换的多种价值观在相同的指令。 有很多的组件,用于这一点(大多是用于解码转换输出的频整数样品);检查它的一些例子。

一个常用的伎俩纯x86/x87码是力的尾数的一部分浮动来表示int。32位的版本如下。

64位版本是类比.Lua版本张贴上面是速度更快,但依靠的是截断的双于一个32位的结果,因此,它需要x87单位被设为双精度,并不能适用于双到64位int转换。

好的事情关于这个代码是这完全是便携式对所有平台符合IEEE754,唯一的假设是浮点四舍五入的模式设置,最近的。注:便携式的意义上,它编制和工作。平台的其他比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,规划行程),可以允许的编译器,来使用其FISTTP指令(即-msse3为海湾合作委员会)。它似乎要做的事情一样它总是应该已经完成:

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

注意FISTTP不同FISTP(即具有自己的问题,导致缓慢).它涉及的一部分SSE3但实际上是(仅)X87侧改进。

其他然后X86CPU是可能会做的转换就好了,反正。:)

处理与SSE3支持

有一个指令转换成一个浮点运到一个int在大会:使用FISTP指令。它持久性有机污染物的值浮点叠,将其转换为一个整数,然后储存在指定的地址.我不认为会有更快的方法(除非你使用扩展的指令集样试试吧或证,我不熟悉).

另一个指令,拳头、树叶的价值在FP堆但我不确定它的工作与四字的大小目标。

Lua码基具有以下段做到这一点(查在src/luaconf.h从www.lua.org).如果你找到(如此认为)更快的方法,我肯定他们会很高兴.

哦, 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

我假设截断是必需的,同样,如果一个写道: i = (int)f 在"C"。

如果你有SSE3,可以使用:

int convert(float x)
{
    int n;
    __asm {
        fld x
        fisttp n // the extra 't' means truncate
    }
    return n;
}

交替,SSE2(或在其中64内联件可能不适用),可以用几乎快:

#include <xmmintrin.h>
int convert(float x)
{
    return _mm_cvtt_ss2si(_mm_load_ss(&x)); // extra 't' means truncate
}

在旧计算机有一个选项,设置四舍五入的方式的手动和执行转换,使用的普通 fistp 指令。这很可能只会工作的阵列的浮动,否则必须采取不使用任何构造,将使改变编译器四舍五入的方式(例如铸件)。它是这样的:

void Set_Trunc()
{
    // cw is a 16-bit register [_ _ _ ic rc1 rc0 pc1 pc0 iem _ pm um om zm dm im]
    __asm {
        push ax // use stack to store the control word
        fnstcw word ptr [esp]
        fwait // needed to make sure the control word is there
        mov ax, word ptr [esp] // or pop ax ...
        or ax, 0xc00 // set both rc bits (alternately "or ah, 0xc")
        mov word ptr [esp], ax // ... and push ax
        fldcw word ptr [esp]
        pop ax
    }
}

void convertArray(int *dest, const float *src, int n)
{
    Set_Trunc();
    __asm {
        mov eax, src
        mov edx, dest
        mov ecx, n // load loop variables

        cmp ecx, 0
        je bottom // handle zero-length arrays

    top:
        fld dword ptr [eax]
        fistp dword ptr [edx]
        loop top // decrement ecx, jump to top
    bottom:
    }
}

注意,联件只适用于微软的Visual Studio汇编者(也许Borland),它就必须重写,以GNU会为了汇编与海湾合作委员会.该SSE2解决与内部函数应该相当的便携式,但是。

其他四舍五入的模式都是可能由不同的SSE2内部函数或通过手动设置FPU控制字四舍五入到一个不同的模式。

如果你真的关心的速度,此确保您的编译器产生的拳头指令。在MSVC你可以这样做/QIfist, 看看这MSDN概述

你也可以考虑使用SSE内部指令以为你做的工作,请参阅本文从英特尔: http://softwarecommunity.intel.com/articles/eng/2076.htm

自从MS scews我们的内联会64和迫使我们要使用内部函数的,我抬起头来,其使用。 MSDN医生_mm_cvtsd_si64x 一个例子。

例的工作,但是可怕的效率低下,使用一个不结盟负载的2倍,在那里我们需要的只是一个单一的负荷,所以摆脱的额外准的要求。然后很多不必要的负载和重新装入生产,但他们可以消除如下:

 #include <intrin.h>
 #pragma intrinsic(_mm_cvtsd_si64x)
 long long _inline double2int(const double &d)
 {
     return _mm_cvtsd_si64x(*(__m128d*)&d);
 }

结果是:

        i=double2int(d);
000000013F651085  cvtsd2si    rax,mmword ptr [rsp+38h]  
000000013F65108C  mov         qword ptr [rsp+28h],rax  

在四舍五入的方式可以是设定没有内联会,例如

    _control87(_RC_NEAR,_MCW_RC);

在四舍五入到最近的是默认(无论如何)。

该问题是否设置的四舍五入的方式在每一个打电话或以假定这将是恢复(第三方的库)会必须回答的经验,我猜。你将必须包括 float.h 对于 _control87() 和相关的常数。

而且,不,这不会的工作中的32位,以继续使用FISTP指令:

_asm fld d
_asm fistp i

一般来说,你可以信任的编译器是有效和正确的。那里通常是没有什么可获得了通过自己的职能,东西已经存在的编译器。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top