如果设置了任何位则返回1,否则使用逻辑运算返回0

时间:2013-12-11 12:58:40

标签: bit logical-operators

编辑:重点是回答不提供替代品的问题,比如我们有肉而不是鱼,我知道有更简单的替代方案

非常感谢abelenky的回答以及David Norris


对于指定的号码,如果该号码不为0,我想返回1,否则返回0,而不必使用for...loopifbool

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.ToIntConvert.ToBoolean方法可用于此但我不想要使用它们。

6 个答案:

答案 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去除剩余的比特。

同样的想法可以适用于其他尺寸的数字类型(ulongushort等)或签名类型。

答案 5 :(得分:-2)

它不能在单个逻辑操作中完成 - 所有逻辑操作都是按位,在输入上像for循环一样迭代,或者它们是累积的,这也无助于解决问题。你需要一个条件(if / then)才能正确解决这个问题......