【问题标题】:Efficient bitwise operation to find the index of the left|right most bit set查找最左|最右位集的索引的高效按位运算
【发布时间】:2013-01-21 10:23:27
【问题描述】:

C++ 中,我可以使用编译器特定的内部函数来查找最左|最右位集,如thread 所示。

C# 有类似的吗?或者我需要遍历所有位来实现这一点?

【问题讨论】:

标签: c# bit-manipulation performance


【解决方案1】:

给你。 Implementations adapted from here.

// Implementation of Least|Most SigBitSet from http://aggregate.org/MAGIC/

using System;

namespace Demo
{
    internal class Program
    {
        private static void Main()
        {
            int value = 0x0ff0; // 0000111111110000

            Console.WriteLine(LeastSigBitSet(value).ToString("x")); // 0x0010
            Console.WriteLine(MostSigBitSet(value).ToString("x"));  // 0x0800
        }

        public static int LeastSigBitSet(int value)
        {
            return (value & -value);
        }

        public static int MostSigBitSet(int value)
        {
            value |= (value >> 1);
            value |= (value >> 2);
            value |= (value >> 4);
            value |= (value >> 8);
            value |= (value >> 16);

            return (value & ~(value >> 1));
        }
    }
}

还有 unsigned int 版本(可能是你想要的):

using System;

namespace Demo
{
    internal class Program
    {
        private static void Main()
        {
            uint value = 0x00ffff00; // 00000000111111111111111100000000

            Console.WriteLine(LeastSigBitSet(value).ToString("x")); // 0x0000100
            Console.WriteLine(MostSigBitSet(value).ToString("x"));  // 0x0800000
        }

        public static uint LeastSigBitSet(uint value)
        {
            return (value & 0u-value);
        }

        public static uint MostSigBitSet(uint value)
        {
            value |= (value >> 1);
            value |= (value >> 2);
            value |= (value >> 4);
            value |= (value >> 8);
            value |= (value >> 16);

            return (value & ~(value >> 1));
        }
    }
}

【讨论】:

  • 有趣。在 uint 的情况下,LeastSigBitSet 方法中,您对两个 longInt64,有符号的 64 位整数)进行按位“与”,然后缩小为 uint (UInt32)。但你也可以说return value & 0u - value;,然后一切都将是 32 位的。但是,它要求溢出检查上下文为unchecked(通常是这样)。
  • 好点。我们也可以把它改成“return (uint)((int)value & -(int)value);”,这样也避免了转换成64位。不过我更喜欢你的短版——我会更新我的答案。
  • 我可能在这里遗漏了一些东西 - 但 (value&(~value+1)) 有什么问题?对于111111110000,它将显示16
  • @RoyiNamir 这是为LeastSigBitSet() 我假设的。好吧,(value&(~value+1)) 使用 AND、NOT 和 ADD。我的(value & 0u-value) 只使用 AND 和 SUBTRACT。因此效率更高。
  • @MatthewWatson 是的。少操作我同意。但关于你的代码 - 你为什么不做 value & -value ?但是(value & 0u-value)
【解决方案2】:

对于 ffs 之类的东西,无法访问特定于编译器的“内置”指令。您必须使用位掩码和移位操作等常规代码实现。但是,这并不一定意味着您需要遍历所有位:其中许多方法都有一些可怕的“常规”实现,疯狂地“添加一些不明显的奇异常量”,旨在删除大部分分支和迭代,这在 C# 中会非常好。如果您移植其中一个,要记住的主要事情是知道它是使用“有符号”还是“无符号”右移;如果它使用“签名”,请使用int(等);如果是“未签名”,请使用uint(等)。

【讨论】:

  • 谢谢..你个人知道(或有参考)任何“这些方法的可怕聪明的“常规”实现”来建议我吗?
  • +1 Sensibile 答案,它具有对ffs 的合法使用,并不意味着通常... :-D
【解决方案3】:

这里有很多人有复杂的解决方案......他说“高效”,所以如果他们能帮你解决问题,我会选择这些。

lsb=i&-i;
msb=(int)(((double)i >> 20) - 1023);

【讨论】:

    猜你喜欢
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2013-03-22
    相关资源
    最近更新 更多