快速浮点到整数转换(截断)

问题描述 投票:0回答:4

我正在寻找一种以快速且可移植(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));
}
c optimization floating-point data-conversion truncate
4个回答
4
投票

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

当使用 SSE 而不是 x87 指令时,可以在不更改控制字的情况下进行截断。您可以使用编译器选项(如 GCC 中的

-mfpmath=sse -msse -msse2
)或将代码编译为 64 位来完成此操作。

SSE3指令集有

FISTTP
指令可以在不改变控制字的情况下转换为带截断的整数。如果指示采用 SSE3,编译器可能会生成此指令。

或者,C99

lrint()
函数将使用当前舍入模式转换为整数(舍入到最接近的值,除非您更改它)。如果删除
copysignf
术语,则可以使用此选项。不幸的是,十几年过去了,这个功能仍然没有普及。


3
投票

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


2
投票

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


0
投票

您可以通过使用

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

© www.soinside.com 2019 - 2024. All rights reserved.