我有一个变量a
,它只能有两个值x1
或x2
。如何在这些值之间切换a
。我想出了这个。还有其他更有效的方法吗?
a = (a == x1 ? x2: x1);
答案 0 :(得分:13)
(高度)不太可能是你的瓶颈,但你可以使用XOR
方法:
togglex1x2 = (x1 ^ x2); // This is the combined toggle value
a = x1; // Initialise to either x1 or x2
a ^= togglex1x2; // toggles
a ^= togglex1x2; // toggles
...
[你应该首先编写可以理解的代码,并且只有在你测量了瓶颈时才进行优化(然后仔细检查它是你认为的位置!),如果你进行了优化,请确保用推理进行评论。 ]
答案 1 :(得分:6)
尝试这样的事情。将在x1和x2之间切换
a = (x1 + x2) - a;
答案 2 :(得分:3)
如果没有上下文,很难预测哪种方法更好 - 最大的未知是这个操作的关键方式 - 是否是延迟限制(例如,如果你在进行长时间的数据依赖性计算时)这个代码),或者可能是带宽关键(你正在交换许多不相关的元素,并开始运行你的资源)。
尝试对此处提出的解决方案进行基准测试。 请参阅此代码,例如:
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 <main>:
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 <main+0x28>
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 <main+0x20>
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 <main+0x38>
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
最后,倒置:))
这表明根据给定操作的方式,您可以获得不同的性能结果 在你的程序中使用。在没有其余代码的情况下对单个方法进行基准测试没有太大意义(不是我们不这样做,只是你需要用一大块盐来获取任何结果)。
当然,这只是为了讨论,很可能这段代码甚至不是远程瓶颈......
答案 3 :(得分:3)
另一种方法是在0和1之间切换索引,并用以下内容索引数组:
int main() {
int const values[] = {0x55, 0xaa};
int selector = 0;
selector ^= 1; // toggle index
int value = values[selector]; // select value
}
答案 4 :(得分:2)
所以你对它进行了基准测试,这是瓶颈,对吗?
哦,好吧,没有...然后忘记效率。这已经是一个非常小的表达式,可以快速评估。
顺便说一句,还有其他方法,但我不确定1.它们真的更快,2。如果它们更快,它真的很重要,3。如果它们较慢,可读性惩罚值得权衡
例如:
#define FIRST 42
#define SECOND 1337
/* initialize */
int x = FIRST;
/* toggle */
x = FIRST + SECOND - x;