Cod*_*cks 2 c++ ternary-operator conditional-operator c++11
是否有可能为三元运算符设置空白的第2或第3个参数,或者是否具有非特定于上下文的参数并且意味着"什么都不做"?在下面的例子中,我想要一个三元运算符,如果它是偶数,则将整数变量乘以2,否则不执行任何操作.除了自我赋值,增加或减去零,或乘以或除以1之外,我无法想到第三个参数.无论如何,它们都是特定于上下文的.我想要一些对所有三元运营商都"无所事事"的东西.我试着将参数留空,但不会编译.
#include <iostream>
int main()
{
int x = 5;
(x % 2 == 0) ? x *= 2 : x = x; // or x += 0, x -= 0, x *= 1, or x /= 1
std::cout << x << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
是否有任何解决方案不涉及已经存在的变量,函数或对象的重述?例如,考虑两个函数foo和goo,那里的foo回报bool.假设由于某种原因,不能再次调用函数,例如在后续调用中更改状态.
int main()
{
( foo() ) ? goo() : ; // won't compile
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您要使用三元运算符,您可能希望分配其结果:
x = (x % 2 == 0) ? 2 * x : x;
Run Code Online (Sandbox Code Playgroud)
就个人而言,我想我只是使用一点点数学:
x <<= ((x & 1) ^ 1);
Run Code Online (Sandbox Code Playgroud)
x&1给出最低有效位x,如果x是奇数则为1,如果是偶数则为0.该^ 1部分翻转该位,因此如果x是偶数则给出1 ,如果x是奇数则给出0 .然后我们x向左移动那么多位.0位移位显然x保持不变.左移一位乘以x2.
至于后者为什么(或者至少可能)更可取,它主要归结为在这种情况下你是否真的关心表现的问题.如果你遇到性能无关紧要的情况,那么if ((x%2)==0) x *= 2;可能是你最好的选择.
我至少猜到,问题的至少部分原因是对效率的关注.如果是这样,纯粹的数学方法可能是更好的选择.例如,让我们考虑VC++为这两个代码生成的代码:
; mathematical version:
mov eax, DWORD PTR _x$[esp-4]
mov ecx, eax
not ecx
and ecx, 1
shl eax, cl
Run Code Online (Sandbox Code Playgroud)
[注意:对于这个源代码,g ++生成几乎相同的目标代码].
忽略x从存储器加载的(可能的)时间,这应该在几乎任何英特尔处理器上执行不超过4个时钟周期回到386左右.更好的是,我希望任何编译器都可以生成任何处理器来生成非常相似的结果 - 几乎任何合理的处理器从源代码到汇编语言的直接,字面翻译将在四个指令中进行实际数学运算,每个指令都尽可能简单快速.
使用该if语句的版本如下:
; Line 2
mov ecx, DWORD PTR _x$[esp-4]
mov eax, ecx
and eax, -2147483647 ; 80000001H
jns SHORT $LN5@f
dec eax
or eax, -2 ; fffffffeH
inc eax
$LN5@f:
lea eax, DWORD PTR [ecx+ecx]
je SHORT $LN1@f
; Line 3
mov eax, ecx
$LN1@f:
Run Code Online (Sandbox Code Playgroud)
随着编译的进行,这也不算太糟糕.它至少避免了div这将是实现一个明显的方式%2.不幸的是,它仍然不够聪明,没有竞争力 - 它仍然有几个分支,其中一个可能不会很容易预测,所以大约一半的时间我们将支付错误预测分支的价格.
根据编译器的不同,您可以(并且将会)看到比这更好的内容.例如,使用g ++,我得到这个:
mov eax, DWORD PTR [ebp+8]
and eax, 1
test eax, eax
jne L2
sal DWORD PTR [ebp+8]
L2:
mov eax, DWORD PTR [ebp+8]
Run Code Online (Sandbox Code Playgroud)
虽然肯定比VC++对这个代码做得更好,但它仍然远不及数学版本那么好.特别地,除非该最低有效位是相当可预测的偶数或奇数,否则该分支可能在大约一半的时间内被mi预测.
底线:在最好的情况下,这可能接近于匹配数学版本 - 但这将取决于编译器和输入数据协作.除了最偶然的编译器和输入数据组合之外,它几乎肯定会慢到至少2倍,而10倍甚至不会令人感到意外.
当然,根据我使用的标志,编译器版本等,我可能能够从任何编译器中获得比实际更好的结果.通过一些持久性,我甚至可以得到与代码的数学版本相同的结果.除非我非常了解目标编译器和CPU,否则我会非常不确定即使获得了很好的结果 - 而且他们更有可能让我感觉非常苗条.
| 归档时间: |
|
| 查看次数: |
3822 次 |
| 最近记录: |