出于好奇。如果我有类似的东西:
if(x < 0)
x = 0;
if(x > some_maximum)
x = some_maximum;
return x;
有没有办法不分支?这是c ++。
附录:我的意思是装配中没有分支指令。这是一个MIPS架构。
答案 0 :(得分:28)
有些技巧可以找到两个数字的最小值或最大值,因此您可以使用它们来查找min(max(x, 0), some_maximum)
。来自here:
y ^ ((x ^ y) & -(x < y)); // min(x, y)
x ^ ((x ^ y) & -(x < y)); // max(x, y)
正如消息来源所述,尽管有分支
,但以正常方式执行它可能会更快答案 1 :(得分:13)
这将取决于编译器和处理器,但如果使用?:
,它可以转换为不使用分支的条件移动(至少在基于Intel的处理器上)。
x = x < 0 ? 0 : x;
x = x > max ? max : x;
这可以使用CMOV
指令(参见http://www.intel.com/software/products/documentation/vlin/mergedprojects/analyzer_ec/mergedprojects/reference_olh/mergedProjects/instructions/instruct32_hh/vc35.htm),其目的是避免分支(以及分支预测惩罚)。
修改:您可能会对此thread感兴趣。基准测试表明,条件移动只会在不可预测的分支上提供速度增益,而高度可预测的分支(例如长时间循环的分支)更喜欢标准方法。
答案 2 :(得分:3)
使用三元运算符:)
return x < 0 ? 0 : x > some_maximum ? : some_maximum : x;
答案 3 :(得分:2)
取决于您的架构。至少对于ARM,编译器可能会发出有条件执行的指令,并且生成的机器代码不会包含分支。我想不出一个在C程序中明确表达的好方法。
答案 4 :(得分:2)
在C ++ 17中,您可以使用std::clamp
在标题
中定义Comparator<Object> yourComparator = ...; BiPredicate<Object,Object> bip = (d1,d2) -> comp.compare(d1,d2) == 0; List<Object> data = ...; List<Object> result = data.stream().pairMap(bip).collect(Collectors.toList());
<algorithm>
- 如果v比较小于lo,则返回lo;否则,如果比较 小于v,返回hi;否则返回v。使用operator <来 比较这些值。
- 与(1)相同,但是使用comp来比较值。
答案 5 :(得分:1)
如果可以限制为2(非包含)的幂,那么只需使用
int newx = x & ((highest power of 2) - 1)
不太确定要处理(如果x&lt; 0情况)或通用(x&lt; n case)
答案 6 :(得分:1)
对于像这样的未来问题,位黑客页面可能很有用:http://graphics.stanford.edu/~seander/bithacks.html。
由于已经发布了min和max的bithack,这里有一个不同的:
// CHAR_BIT is number of bits per byte.
// sign = 1 if x < 0, sign = 0 otherwise (according to the page above)
int sign = (int)((unsigned int)((int)x) >> (sizeof(int) * CHAR_BIT - 1));
int y = (1-sign)*x; // if x < 0, then y = 0, else y = x.
// Depending on arch, the below _might_ cause a branch.
// (on x64 it does not cause a branch, not sure about MIPS)
int z = !(y/some_maximum); // if 0 <= y < some_maximum, z = 1, else z = 0
int ret = z*y + (1-z)*some_maximum; // if z =1, then ret = y; else ret = some_maximum.
return ret;
我刚试了一下,它适用于我所拥有的几个测试用例。
这是我的计算机(intel arch)的汇编代码,它没有显示分支。
int cap(int x)
{
00F013A0 push ebp
00F013A1 mov ebp,esp
00F013A3 sub esp,0FCh
00F013A9 push ebx
00F013AA push esi
00F013AB push edi
00F013AC lea edi,[ebp-0FCh]
00F013B2 mov ecx,3Fh
00F013B7 mov eax,0CCCCCCCCh
00F013BC rep stos dword ptr es:[edi]
int some_maximum = 100;
00F013BE mov dword ptr [some_maximum],64h
// CHAR_BIT is number of bits per byte.
// sign = 1 if x < 0, sign = 0 otherwise (according to the page above)
int sign = (int)((unsigned int)((int)x) >> (sizeof(int) * CHAR_BIT - 1));
00F013C5 mov eax,dword ptr [x]
00F013C8 shr eax,1Fh
00F013CB mov dword ptr [sign],eax
int y = (1-sign)*x; // if x < 0, then y = 0, else y = x.
00F013CE mov eax,1
00F013D3 sub eax,dword ptr [sign]
00F013D6 imul eax,dword ptr [x]
00F013DA mov dword ptr [y],eax
// Depending on arch, the below _might_ cause a branch.
// (on x64 it does not cause a branch, not sure about MIPS)
int z = !(y/some_maximum); // if 0 <= y < some_maximum, z = 1, else z = 0
00F013DD mov eax,dword ptr [y]
00F013E0 cdq
00F013E1 idiv eax,dword ptr [some_maximum]
00F013E4 neg eax
00F013E6 sbb eax,eax
00F013E8 add eax,1
00F013EB mov dword ptr [z],eax
int ret = z*y + (1-z)*some_maximum; // if z =1, then ret = y; else ret = some_maximum.
00F013EE mov eax,dword ptr [z]
00F013F1 imul eax,dword ptr [y]
00F013F5 mov ecx,1
00F013FA sub ecx,dword ptr [z]
00F013FD imul ecx,dword ptr [some_maximum]
00F01401 add eax,ecx
00F01403 mov dword ptr [ret],eax
return ret;
00F01406 mov eax,dword ptr [ret]
}
00F01409 pop edi
00F0140A pop esi
00F0140B pop ebx
00F0140C mov esp,ebp
00F0140E pop ebp
00F0140F ret
答案 7 :(得分:0)
x = min(max(x,0),100);
分支隐藏在具有普通名称的函数内。
建议创建clip_by模板。
答案 8 :(得分:0)
x = ((int)(x > some_maximum)) * some_maximum
+ ((int)(x > 0 && x <= some_maximum)) * x;