更快的是:比较然后改变,或者立即改变
What is faster: compare then change, or change immediately?
让我进行非常快速的循环,我必须确保在每个循环的末尾,变量a
是SOMEVALUE
。什么会更快?
if (a != SOMEVALUE) a = SOMEVALUE;
或者立即进行
a = SOMEVALUE;
它是float/int/bool/语言特定的吗?
更新:a
是基元类型,而不是类。TRUE比较的可能性为50%。我知道算法是使循环快速的原因,所以我的问题也是关于编码风格。
更新2:感谢大家的快速回答!
在几乎所有情况下,仅设置该值会更快。
当你必须与其他cpu处理缓存线共享时,或者如果"a"在某种特殊类型的内存中,它可能不会更快,但可以肯定的是,分支预测失误可能是比缓存共享更常见的问题。
此外,更小的代码更好,不仅对缓存,而且对代码的可理解性也更好。
如果有疑问-简介。
一般的答案是分析这类问题。然而,在这种情况下,可以进行简单的分析:
每个测试都是一个分支。每个分支都会产生轻微的性能损失。然而,我们有分支预测,这个惩罚会随着时间的推移而摊销,这取决于循环的迭代次数和预测正确的次数。
换句话说,如果在循环过程中对a
进行了多次更改,那么使用if
的代码的性能很可能会更差。另一方面,如果值很少更新,那么这两种情况之间的差异将非常小。
尽管如此,正如您的代码片段所示,只要您不关心以前的值,立即更改是更好的,应该使用它。
立即更改的其他原因:它会导致代码更小,从而获得更好的缓存位置,从而获得更高的代码性能。更新a
会使缓存线失效并导致性能下降的情况非常罕见。不过,如果我没记错的话,这只会在多处理器的情况下给你字节,而且很少。
请记住,在某些情况下,两者并不相似。比较NaN
s是未定义的行为。
此外,这个注释只处理C的情况。在C++中,可以有赋值运算符/副本构造函数比测试相等性花费更长时间的类。在这种情况下,您可能需要先进行测试。
考虑到您的更新,只要您确信不处理未定义的行为(浮点),最好简单地使用赋值。编码风格也更好,更容易阅读。
您应该对其进行配置。
我的猜测是,根据测试正确的频率(这是由于分支预测),差异很小。
当然,只需设置它就可以获得最小的绝对代码大小,从而为更有趣的代码释放指令缓存。
但是,你应该再次对其进行分析。
如果答案不是a = somevalue
,我会感到惊讶,但这个问题没有通用的答案。首先,它取决于复制的速度与相等比较的速度。如果平等比较非常快,那么你的第一个选择可能会更好。其次,和往常一样,它取决于您的编译器/平台。回答这些问题的唯一方法是尝试这两种方法并计时。
正如其他人所说,分析它将是最容易判断的方法,因为它在很大程度上取决于你向它抛出的输入类型。然而,如果你考虑这两种算法的计算复杂性,你向它扔的输入越多,它们之间可能的差异就越小。
当您要求使用C++程序时,我假设您正在将代码编译为本机指令。
在任何情况下,直接赋值而不进行任何比较都应该快得多。要比较这些值,应该将值a和SOEVALUE都传输到寄存器,并且必须执行一条机器指令cmp()。
但在后面直接赋值的情况下,您只需将一个值从一个内存位置移动到另一个。
只有当内存写入的成本明显高于内存读取时,分配才会变慢。我不认为会发生这种事。
评测代码。相应地更改
对于基本类型,无分支选项应该更快。例如,MSVS并没有优化分支。
话虽如此,这里有一个比较版本更快的例子:
struct X
{
bool comparisonDone;
X() : comparisonDone(false) {}
bool operator != (const X& other) { comparisonDone = true; return true; }
X& operator = (const X& other)
{
if ( !comparisonDone )
{
for ( int i = 0 ; i < 1000000 ; i++ )
cout << i;
}
return *this;
}
}
int main()
{
X a;
X SOMEVALUE;
if (a != SOMEVALUE) a = SOMEVALUE;
a = SOMEVALUE;
}
立即更改通常更快,因为它不涉及代码中的分支
正如下面的评论和其他人的回答,这确实取决于许多变量,但IMHO真正的问题是:你在乎以前的值是多少吗?如果你是,你应该检查,否则,你不应该。
if
实际上可以被一些编译器"优化掉",基本上将if
变成代码噪声(对于正在阅读它的程序员来说)。
当我使用GCC为x86编译以下函数时(使用-O1
,这是一个非常合理的优化级别):
int foo (int a)
{
int b;
if (b != a)
b = a;
b += 5;
return b;
}
GCC只是"优化"if
和赋值,并简单地使用参数进行添加:
foo:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
popl %ebp
addl $5, %eax
ret
.ident "GCC: (GNU) 4.4.3"
具有或不具有CCD_ 15生成完全相同的代码。
- 变量没有改变?通过向量的函数调用
- 如何改变c++应用程序的视觉效果
- C++在不同线程中改变向量
- 如何访问和改变存储在矢量C++中的对象
- 地图计数确实很重要,或者只是检查是否存在
- 在C++行尾写一个分号或多个分号是否会改变任何内容
- 错误 C2679:二进制"<<":未找到采用类型 'std::string_view' 的右侧操作数的运算符(或者没有可接受的转换)
- 为什么文件不是由 F 流创建的,或者即使它是输出只是垃圾值?
- 为什么字符串的 move() 会改变内存中底层数据的位置?
- 为什么 c++ 动态数组的大小没有改变?
- 为什么提升图库的 read_graphviz() 函数会改变节点的索引
- C2678 二进制 '==':未找到采用 'Card' 类型左操作数的运算符(或者没有可接受的转换)
- 使用宏编译时使用用户定义的数学函数,或者仅使用 c++ 中标准数学库中的函数
- 在向量内更改变量的值不会改变其在向量外的值
- 为什么 GCC 不能假设 std::vector::size 在这个循环中不会改变?
- 改变或缩放两个正态分布以具有特定的相关系数
- 如何仅使用一次固定<<设置精度(2)?或者至少恢复到默认行为?
- 当我使用CHAR_INFO结构时,控制台会无缘无故地改变颜色
- 更快的是:比较然后改变,或者立即改变
- 如果vector改变,迭代器是否指向相同的元素?或者怎么做