编辑:重点是回答不提供替代品的问题,比如我们有肉而不是鱼,我知道有更简单的替代方案
非常感谢abelenky的回答以及David Norris
对于指定的号码,如果该号码不为0,我想返回1,否则返回0,而不必使用for...loop
,if
或bool
。
在this document中,除了0:
之外它确实可以正常工作Bit Hack#8。向右传播最右边的1位。
y = x | (x-1)
...
这不是一个干净的黑客,因为如果x = 0,它会产生全1。
我想出的最好的事情是以下(对于字节类型):
for (int i = 0; i < 256; i++)
{
int o =
((i & (1 << 7)) >> 7) |
((i & (1 << 6)) >> 6) |
((i & (1 << 5)) >> 5) |
((i & (1 << 4)) >> 4) |
((i & (1 << 3)) >> 3) |
((i & (1 << 2)) >> 2) |
((i & (1 << 1)) >> 1) |
((i & (1 << 0)) >> 0);
Debug.Assert((i == 0 & o == 0) || (i != 0 && o == 1));
Console.WriteLine(@"i {0:D3} o {1:D3}", i, o);
}
但是,查看反汇编会产生所有这些代码:
int o =
((i & (1 << 7)) >> 7) |
((i & (1 << 6)) >> 6) |
((i & (1 << 5)) >> 5) |
((i & (1 << 4)) >> 4) |
((i & (1 << 3)) >> 3) |
((i & (1 << 2)) >> 2) |
((i & (1 << 1)) >> 1) |
((i & (1 << 0)) >> 0);
0000021f mov eax,dword ptr [ebp-6Ch]
00000222 mov edx,80h
00000227 and eax,edx
00000229 sar eax,7
0000022c mov edx,dword ptr [ebp-6Ch]
0000022f mov ecx,40h
00000234 and edx,ecx
00000236 sar edx,6
00000239 or eax,edx
0000023b mov edx,dword ptr [ebp-6Ch]
0000023e mov ecx,20h
00000243 and edx,ecx
00000245 sar edx,5
00000248 or eax,edx
0000024a mov edx,dword ptr [ebp-6Ch]
0000024d mov ecx,10h
00000252 and edx,ecx
00000254 sar edx,4
00000257 or eax,edx
00000259 mov edx,dword ptr [ebp-6Ch]
0000025c mov ecx,8
00000261 and edx,ecx
00000263 sar edx,3
00000266 or eax,edx
00000268 mov edx,dword ptr [ebp-6Ch]
0000026b mov ecx,4
00000270 and edx,ecx
00000272 sar edx,2
00000275 or eax,edx
00000277 mov edx,dword ptr [ebp-6Ch]
0000027a mov ecx,2
0000027f and edx,ecx
00000281 sar edx,1
00000283 or eax,edx
00000285 mov edx,dword ptr [ebp-6Ch]
00000288 mov ecx,1
0000028d and edx,ecx
0000028f or eax,edx
00000291 mov dword ptr [ebp-70h],eax
是否有另一种方法使用一些不会产生那么多指令的聪明的逻辑运算?
注意,这里的要点不是为了减少为了性能而减少指令的数量,而是要知道是否有更简单的方法来执行此操作。
有些人暗示要将数字转换为布尔值,但不幸的是,这在C#中是不可能的,还有Convert.ToInt
和Convert.ToBoolean
方法可用于此但我不想要使用它们。
答案 0 :(得分:4)
您的问题是: “如果设置了任何位则返回1,否则为0”
答案是:
int AnyBitSet(int x)
{
return (x == 0)? 0 : 1;
}
(也许你想澄清一下你的问题?)
答案 1 :(得分:2)
// Returns 1 for any non-zero number, 0 for zero.
int AnyBitSet(int x)
{
return !!x;
}
如果X
为零,!X
为1,!!X
为零。
如果X
非零,则!X
为0,!!X
正好为1,无论原始x
如何。
答案 2 :(得分:2)
好的,如何使用.NET Framework ...
return Math.Abs(Math.Sign(x));
答案 3 :(得分:1)
int IsZero(int x)
{
return ((x & -x) - 1) >> 31;
}
x&amp;如果存在,则-x隔离最低有效值1(情况a)否则为0(情况b)。然后减去1将删除符号位(情况a)或结果为-1(情况b)。最终的移位给出了符号位,在情况a为0,在情况b为1。这会产生与你问的相反的结果,但它总是可以切换。
int IsNonZero(int x)
{
return IsZero(x) ^ 1;
}
答案 4 :(得分:0)
这个怎么样:
public static uint OneIfNonzero( uint x )
{
x |= x >> 16;
x |= x >> 8;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
return x & 1;
}
这里的想法是使用一系列OR将所有位传播到最低有效位。在一系列OR完成之后,最低有效位等于所有32个原始位的OR。然后使用最终的AND去除剩余的比特。
同样的想法可以适用于其他尺寸的数字类型(ulong
,ushort
等)或签名类型。
答案 5 :(得分:-2)
它不能在单个逻辑操作中完成 - 所有逻辑操作都是按位,在输入上像for循环一样迭代,或者它们是累积的,这也无助于解决问题。你需要一个条件(if / then)才能正确解决这个问题......