c++ 如何处理 0*(大表达式)

How does c++ handle 0*(large expression)

本文关键字:表达式 处理 何处理 c++      更新时间:2023-10-16

关于速度,如果我需要计算一个大表达式,比如:

switch1*(large expression 1)+switch2*(large expression 2)

根据我的输入,switch1可以是01switch2也可以。对于 c++ 来说,最快的做法是什么,做一个 if 语句或像上面一样写下来?

所以,本质上你问的是短路计算,你问的是除了布尔表达式之外,C++是否对算术表达式这样做。

证明否定有点困难,但据我所知,C++只对逻辑表达式进行短路计算,所以算术表达式没有等价物。 此外,我可以想到很多代码,如果以短路方式计算算术表达式,这些代码会严重中断,所以我认为这永远不会如此。

从理论上讲,如果编译器可以证明它没有副作用,则可以生成代码以避免计算表达式。但实际上,不太可能添加代码来检查值是否为零,因为它没有理由认为它会为零。

另一方面,逻辑运算(||&&)保证在C++短路。所以你应该使用它们。

result = 0;
if(switch1) {
result += large_expresion_1();
}
if(switch2)
result += large_expression2();
}

但是,如果您要优化"大型表达式",请务必检查计算它们是否实际上更快,然后以无分支的方式添加它们。 例如类似的东西

result = ((-(uint64_t)(switch1)) & large_expression_1) + ((-(uint64_t)(switch2)) & large_expression_2);

这里记录了一堆这样的位黑客: https://graphics.stanford.edu/~seander/bithacks.html

基准测试并分开,阅读生成的汇编语言,以了解编译器实际上为您(或)做了什么。

switch1可以是0也可以是1,也可以是switch2

如果switch1switch2真的只能有01的值,那么它们最好是布尔值而不是整数。

使用布尔开关,您的语句将变为:

result = (switch1 ? (large expression 1) : 0)
+ (switch2 ? (large expression 2) : 0)

在这种情况下,即使不使用表达式的结果,也会计算表达式。避免浪费计算的一个简单明了的方法是显而易见的:

result = 0;
if(switch1) {
result += large expression 1;
}
if(switch2) {
result += large expression 2;
}

您可以通过提取方法来整理它,您将开关传递到这些方法中:

result = guardedLargeExpression1(switch1, otherparams1) 
+ guardedLargeExpression2(switch2, otherparams2);

。跟。。。

int guardedLargeExpression1(bool switch, foo params) {
if(switch) {
return 0;
}
return large expression(...);
}

你也可以用指向函数的指针做一些聪明的事情:

int guardedFunctionCall(bool switch, int *functionptr(foo), foo arg) {
if(switch) {
return 0;
}
return (*functionptr)(arg);
}

。这接近您在 Java 中懒惰地使用Supplier评估代码时会做的事情。

或者,由于您使用的是 C++ 而不是 C,您可以做一些更 OO 的操作,并实际使用 C++ 等价物Supplier: java.util.function.Supplier C++等价物是什么?

if 取决于确切的条件。CPU,编译器,确切的表达式。

如果ifif成为程序集代码中的条件跳转,并且无法预测条件,则可能会减慢程序的速度。

如果条件无法预测,并且"大表达式"实际上很简单,那么做"乘法方式"可能会更快。

但是,如果表达式计算速度很慢,或者if可以完美地进行分支预测(或者它不能编译为条件跳转),那么我认为if方式会更快。

总而言之,您应该尝试这两种解决方案,并检查哪种解决方案更快。