在两个值之间切换整数变量的最简单方法

我有一个变量a ,它只能有两个值x1x2 。 如何在这些值之间切换。 我想出了这个。 还有其他更有效的方法吗?

 a = (a == x1 ? x2: x1); 

它(高度)不太可能是你的瓶颈,但你可以使用XOR方法:

 togglex1x2 = (x1 ^ x2); // This is the combined toggle value a = x1; // Initialise to either x1 or x2 a ^= togglex1x2; // toggles a ^= togglex1x2; // toggles ... 

[您应该首先编写可以理解的代码,并且只有在测量瓶颈时进行优化(然后仔细检查它是您认为的位置!),如果您进行优化,请确保使用推理进行评论。 ]

尝试这样的事情。 将在x1和x2之间切换

 a = (x1 + x2) - a; 

另一种方法是在0和1之间切换索引并使用以下内容索引数组:

 int main() { int const values[] = {0x55, 0xaa}; int selector = 0; selector ^= 1; // toggle index int value = values[selector]; // select value } 

如果没有上下文,很难预测哪种方法更好 – 最大的未知是这个操作的关键方式 – 它是否是延迟限制(例如,如果你使用通过此代码的数据依赖进行长时间的计算)或者可能是带宽关键(你正在交换许多不相关的元素,并开始运行你的资源)。

试图对这里提出的解决方案进行基准测试 看到这段代码,例如:

 int main() { int x1 = 123, x2 = 456; int x1_xor_x2 = x1 ^ x2; int a = x1; int i; for (i = 0; i < 10000; ++i) a = (a == x1 ? x2: x1); for (i = 0; i < 10000; ++i) a ^= x1_xor_x2; printf ("a=%d\n", a); // prevent all this from being optimized out } 

变成(gcc,带-O3):

 0000000000400440 
: 400440: b8 10 27 00 00 mov $0x2710,%eax // loop counter 400445: ba c8 01 00 00 mov $0x1c8,%edx 40044a: be 7b 00 00 00 mov $0x7b,%esi // 123 in esi 40044f: b9 c8 01 00 00 mov $0x1c8,%ecx // 456 in ecx 400454: eb 12 jmp 400468 400456: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 40045d: 00 00 00 400460: 83 fa 7b cmp $0x7b,%edx 400463: 89 ca mov %ecx,%edx 400465: 0f 45 d6 cmovne %esi,%edx // conditional move 400468: 83 e8 01 sub $0x1,%eax 40046b: 75 f3 jne 400460 40046d: b8 10 27 00 00 mov $0x2710,%eax 400472: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 400478: 81 f2 b3 01 00 00 xor $0x1b3,%edx 40047e: 83 e8 01 sub $0x1,%eax // xoring 400481: 75 f5 jne 400478 400483: be 6c 06 40 00 mov $0x40066c,%esi 400488: bf 01 00 00 00 mov $0x1,%edi 40048d: 31 c0 xor %eax,%eax 40048f: e9 9c ff ff ff jmpq 400430 <__printf_chk@plt>

在添加时间检查(并将循环计数增加到100M)后,我上了我的服务器(AMD Opteron 6272):

 first: 0.089000s second: 0.067000s a=123 

这不是很有趣,因为没有消费者需要低延迟数据(因此计算可能缓冲,我们正在检查ALU BW,而不是延迟)

试图在每次迭代时添加sum += a导致delta增加,有利于第一次 -

 first: 0.106000s second: 0.066000s 

但! 因为简单的添加本身并不是非常耗时,尝试使用倒数(浮点和+= 1/a ) - 这个确实需要快速数据:

 first: 0.014000s second: 0.087000s 

最后,倒置:)

这表明根据程序中使用的给定操作的方式,您可以获得不同的性能结果。 在没有其余代码的情况下对单个方法进行基准测试没有太大意义(不是我们不这样做,只是你需要用一大块盐来获取任何结果)。

当然,这都是为了讨论,很可能这段代码甚至不是远程瓶颈。

所以你对它进行了基准测试,这是瓶颈,对吧?

哦,好吧,没有…然后忘记效率。 这已经是一个非常小的表达式,可以快速评估。

顺便说一下,还有其他方法,但我不确定1.它们真的更快,2。如果它们更快,它真的很重要,3。如果它们较慢,可读性惩罚是值得的权衡。

例如:

 #define FIRST 42 #define SECOND 1337 /* initialize */ int x = FIRST; /* toggle */ x = FIRST + SECOND - x;