快速浮点到int转换(截断)

我正在寻找一种以快速便携(IEEE 754)方式将float截断为int方法。 原因是因为在这个函数中,50%的时间都花在了演员身上:

 float fm_sinf(float x) { const float a = 0.00735246819687011731341356165096815f; const float b = -0.16528911397014738207016302002888890f; const float c = 0.99969198629596757779830113868360584f; float r, x2; int k; /* bring x in range */ k = (int) (F_1_PI * x + copysignf(0.5f, x)); /* <-- 50% of time is spent in cast */ x -= k * F_PI; /* if x is in an odd pi count we must flip */ r = 1 - 2 * (k & 1); /* trick for r = (k % 2) == 0 ? 1 : -1; */ x2 = x * x; return r * x*(c + x2*(b + a*x2)); } 

float-> int casts的缓慢主要发生在x86上使用x87 FPU指令时。 要进行截断,FPU控制字中的舍入模式需要更改为舍入到零和后退,这往往非常慢。

使用SSE而不是x87指令时,可以在没有控制字更改的情况下进行截断。 您可以使用编译器选项(如GCC中的-mfpmath=sse -msse -msse2 )或将代码编译为64位来执行此操作。

SSE3指令集具有FISTTP指令,可在不更改控制字的情况下转换为带截断的整数。 如果指示假定SSE3,则编译器可以生成该指令。

或者,C99 lrint()函数将使用当前舍入模式转换为整数(除非您更改它,否则为round-to-nearest)。 如果删除copysignf术语,则可以使用此copysignf 。 不幸的是,这种function在十多年后仍然无处不在。

为了便携,你必须添加一些指令并学习几种汇编语言,但理论上你可以使用一些内联汇编将浮点寄存器的部分移动到eax / rax ebx / rbx并转换你需要的东西,浮动点规格虽然是一个痛苦的屁股,但我很确定如果你用汇编来做你会更快,因为你的需求非常具体,系统方法可能更通用,效率更低的目的

我找到了Sree Kotay的快速截断方法 ,它提供了我所需要的优化。

您可以通过使用frexpf获取尾数和指数来完全跳过转换为int ,并在适当的位位置(使用指数计算)检查原始尾数(使用并union )以确定(象限相关) r