我可以用 AND 替换 if 语句吗?

Can I replace an if-statement with AND?

我的教授曾经说过,if 语句相当慢,应该尽可能避免。我正在用 OpenGL 制作游戏,我需要很多游戏。 在我的测试中,通过短路将 if 语句替换为 AND 是可行的,但它更快吗?

bool doSomething();

int main()
{

  int randomNumber = std::rand() % 10;

  randomNumber == 5 && doSomething();

  return 0;
}

bool doSomething()
{
    std::cout << "function executed" << std::endl;

    return true;
}

我的目的是在渲染器的绘制函数中使用它。我的模型应该有标志,如果标志为真,则应该执行某个函数。

if-statements are rather slow and should be avoided as much as possible.

这是错误的and/or误导。大多数关于程序运行缓慢的简化陈述都是错误的。这个答案也可能有问题。

C++ 语句没有可以归因于它们的速度。重要的是编译程序的速度。这包括汇编语言指令;不是 C++ 语句。

可能更正确的说法是分支指令可以相对较慢(在现代超标量CPU架构上)(当无法预测分支时嗯)(取决于你比较的是什么;有很多东西要贵得多)。

randomNumber == 5 && doSomething();

一个if-statement经常被编译成使用分支指令的程序。 short-circuiting logical-and 操作也经常被编译成使用分支指令的程序。用 logical-and 运算符替换 if-statement 并不是让程序更快的灵丹妙药。

如果你将logical-and生成的程序与替换为if (randomNumber == 5)的相应程序进行比较,你会发现优化器识破了你的把戏并生成了相同的程序集在这两种情况下。

My models are supposed to have flags, if a flag is true, a certain function should execute.

为了避免分支,必须改变前提。与其遍历所有模型的序列、检查标志并有条件地调用函数,您可以创建一个应为其调用函数的所有模型的序列,对其进行迭代,然后无条件地调用函数 -> 无分支。这个替代方案更快吗?维护数据结构肯定会有一些开销,而分支预测器可能已经不需要这样做了。唯一确定的方法是测量程序。

我同意上面的评论,几乎在所有实际情况下,都可以毫不犹豫地使用ifs。
我也同意,对于初学者来说,将精力浪费在优化上并不是一个重要的问题,并且使用逻辑运算符可能会发出类似于 ifs.

的代码

但是 - 这里有一个与一般分支相关的有效问题,因此欢迎有兴趣的人继续阅读。

现代CPU使用我们所说的Instruction pipelining
无需深入了解技术细节:
在每个 CPU 内核中都有一定程度的并行性。 每条汇编指令都由几个阶段组成,在执行当前指令的同时,对下一条指令进行了一定程度的准备。 这称为指令流水线。
这个概念通常被任何类型的分支打破,特别是条件(ifs)。
确实有branch prediction的机制,但只是在一定程度上起作用。

所以虽然在大多数情况下 ifs 是完全可以的,但也有一些情况应该考虑在内。 一如既往,在优化方面,应该仔细分析。

以下面这段代码为例(类似的东西在图像处理等实现中很常见):

unsigned char * pData = ...; // get data from somewhere
int dataSize = 100000000; // something big
bool cond = ...;    // initialize some condition for relevant for all data
for (int i = 0; i < dataSize; ++i, ++pData)
{
    if (cond)
    {
        *pData = 2; // imagine some small calculation
    }
    else
    {
        *pData = 3; // imagine some other small calculation
    }
}

这样做可能更好(即使它包含从软件工程角度来看是邪恶的重复):

if (cond)
{
    for (int i = 0; i < dataSize; ++i, ++pData)
    {
        *pData = 2; // imagine some small calculation
    }
}
else
{
    for (int i = 0; i < dataSize; ++i, ++pData)
    {
        *pData = 3; // imagine some other small calculation
    }
}

我们仍然有一个 if 但它可能只导致分支一次。

在某些[罕见]情况下(需要如上所述的分析)甚至像这样做会更有效:

for (int i = 0; i < dataSize; ++i, ++pData)
{
    *pData = (2 * cond + 3 * (!cond));  
}

我知道这不常见,但几年前我遇到了特定的硬件,其中 2 次乘法和 1 次加法的成本低于分支的成本(由于指令流水线的重置)。此“技巧”还支持对数据的不同部分使用不同的条件值。

底线: if通常是可以的,但要知道有时是有代价的。