7

我有这个 C 函数:

double f(int x)
{
    if (x <= 0)
        return 0.0;
    else
        return x * log(x);
}

我在一个紧密的循环中调用它,并且想摆脱分支以查看它是否可以提高性能。

我不能使用这个:

double f(int x)
{
    return x * log(x);
}

因为它返回NaNx == 0(大约 25% 的时间是正确的。)

有没有另一种方法来实现它,以便它在0何时返回x == 0,但仍然摆脱分支?

(我不太关心负输入,因为这些是错误,而零则不是。)

4

3 回答 3

13

首先注意log(1) = 0。然后你可以把问题写成 x * log(y),如果 x <= 0 则 y = 1,否则等于 x;如果 y = 1,那么 x 无关紧要,因为 log(y)=0。

像 y = (x > 0)*x + (x <= 0) 这样的东西会这样做,然后:

double f(int x) {
    return x * log((x > 0)*x + (x <= 0));
}

这仅取决于 log(1) 和四个整数操作是否比分支差。

于 2012-11-15T18:20:44.397 回答
11

编译器扩展可以在这里提供帮助。在 GCC 中,您可以这样做:

if(__builtin_expect(x > 0, 1)) {
    return x * log(x);
}
return 0.0;

然后 GCC 将生成有利于x > 0 == 1分支的机器代码。

如果您不关心负数,那么您可以将x == 0其视为不太可能的分支:

if(__builtin_expect(x == 0, 0)) {
    return 0.0;
}
return x * log(x);

如果您不在 GCC 上,您应该检查编译器的文档,看看它是否提供了类似的功能。

请注意,它仍然不是无分支的。只是可能的分支需要更少的时间。

于 2012-11-15T18:02:20.703 回答
7

任何无分支代码都必须包含计算x * log(x)以涵盖“正常”情况。

因此,在尝试提出无分支代码之前,请先测量x * log(x)单独的速度。除非它比您拥有的代码快得多,否则这里没有什么重要的收获。我怀疑它不会。

于 2012-11-15T21:10:30.197 回答