【问题标题】:How do I determine the position of the nth most significand bit set in a 64-bit value?如何确定 64 位值中设置的第 n 个最高有效位的位置?
【发布时间】:2009-09-30 07:35:12
【问题描述】:

我在 Java 程序中使用一些长值作为位图。到目前为止,这是我的方法:

public class BitmapUtil
{
    private static final long _B_MASK_LEFT_ON = 0x8000000000000000L;

    public static long setNthMsb(int n)
    {
        return BitmapUtil._B_MASK_LEFT_ON >>> n;
    }

    public static boolean isNthMsbSet(long b, int n)
    {
        return (b & (BitmapUtil.setNthMsb(n))) != 0L;
    }

    public static int getNthMsbPosition(long b, int n)
    {
        int ix = 0;
        while (ix < 64 && n >= 0) {
            if (BitmapUtil.isNthMsbSet(b, ix)) {
                if (n == 0) {
                    return ix;
                } else {
                    n--;
                }
            }
            ix++;
        }
        return -1;
    }
}

我见过这么多聪明的小把戏,我不禁觉得应该有更好的方法。有吗?

【问题讨论】:

  • “ixNthMsbSetPos”? “fIsNthMsbSet”? ......当我呕吐时请原谅我:-)
  • @Stephen C - 好吧,我已经习惯了我们的匈牙利语,以至于我认为方法名称没有任何问题。也许现在对眼睛更友好了? ;-)
  • 这不仅仅是匈牙利语,而是难以理解的命名。为什么不使用像boolean isSet(long number, int bitIndex) 这样的签名。很明显,这样的方法会返回 number 中的 bitIndex'th 位是否已设置,不是吗?
  • @Joren - 感谢您的反馈,非常感谢!但是,很多可读或不可读与您习惯的内容以及您在什么环境中找到内容有关。例如,在处理位模式时,我经常会遇到“我是从左数还是从右数?”这个问题,所以这将是我在isSet(... bitIndex) 中遗漏的一些内容。 OTOH,一直使用匈牙利语,ix(b, n) 的签名已经告诉我基本操作,因为我知道如果我将bn 变成ix 会发生什么。这很像方言:瑞士人说不可能的德语,但他们都听得懂。
  • @Joren - 是的,我知道。 :) 但我试图更笼统一点。它必须是理解代码的 人员。例如,一个西班牙团队可能会选择将所有内容命名为西班牙语,除非有人必须​​理解非母语人士的代码,否则这不会有任何问题。我想这是非常罕见的,但就像没有通用的自然语言一样,也没有天生就比所有其他语言更好的命名约定。那么,像您这样的反馈对于判断您的本地方言的具体程度非常重要。

标签: java bitmap bit-manipulation


【解决方案1】:

我认为这就是你想要的,没有任何关于效率的线索。

//      long val = 0xAF00000000000000L;
        long val = 0x0000000000000001L;
        int n = 2;
        int count = 0;
        int i = 0;
        while (i < 65 && count < n) {
            if ((val & 0x8000000000000000L) != 0) {
                count++;
            }
            val = val << 1;
            i++;
        }

这似乎是从左数,其中 MSB 是位置 1,LSB 是位置 64。如果 i==65,则 n 位未设置。

【讨论】:

  • 至少这比我的解决方案要好,因为它的位移要少得多。 (64 而不是 64 + 63 + ... + 1) 读起来也好一点。
【解决方案2】:

这里有几个不同的快速算法:bit hacks,寻找计算数字的 log 2。

最漂亮的是这个,但它只适用于 32 位数字:

unsigned int v; // find the log base 2 of 32-bit v
int r;          // result goes here

static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

v |= v >> 1; // first round down to power of 2 
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v = (v >> 1) + 1;

r = MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x077CB531U) >> 27];

【讨论】:

  • 不确定我是否理解这一点,但它确实看起来很有趣,+1。 :)
【解决方案3】:

我在 C++ 中找到了 32 位,可以很容易地适应 Java 和 64 位

http://lsjandysf.spaces.live.com/blog/cns!54FF19028BDE00EA!440.entry

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-05
    • 2010-10-19
    • 2012-04-29
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    相关资源
    最近更新 更多