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

时间:2012-02-18 22:22:27

标签: c optimization floating-point truncate

我正在寻找一种以快速便携(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));
}

4 个答案:

答案 0 :(得分:4)

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

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

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

我找到了Sree Kotay的fast truncate method,它提供了我所需的优化。

答案 3 :(得分:0)

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