C语言 f(x) 的无分支实现 := 如果 x == 0 则 0 else (x * log(x))



我有这个C函数:

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

我在一个紧密循环中调用它,并希望摆脱该分支以查看它是否提高了性能。

我不能使用它:

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

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

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

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

首先注意 log(1) = 0。然后你可以把问题写成 x * log(y),其中 y = 1 如果 x <= 0,否则等于 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) 和四个整数运算是否比一个分支差。

编译器

扩展可以在这里提供帮助。在 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 上,您应该检查编译器的文档,看看它是否提供了类似的功能。

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

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

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

最新更新