【问题标题】:Computing the floor log of a binary number计算二进制数的楼层对数
【发布时间】:2013-09-04 21:02:27
【问题描述】:

如果有一个二进制数,在 n 位系统中,则该数的 floor log 定义为该数的 MSB 的索引。现在,如果我有一个二进制数,通过逐位扫描所有位,我可以确定 MSB 的索引,但这需要我订购 n 次。有什么更快的方法可以做到吗?

【问题讨论】:

    标签: algorithm binary logarithm


    【解决方案1】:

    以c#为例,对于一个字节,你可以预先计算一个表,然后进行查找

    internal static readonly byte[] msbPos256 = new byte[256];
    static ByteExtensions() {
        msbPos256[0] = 8; // special value for when there are no set bits
        msbPos256[1] = 0;
        for (int i = 2; i < 256; i++) msbPos256[i] = (byte)(1 + msbPos256[i / 2]);
    }
    
    /// <summary>
    /// Returns the integer logarithm base 2 (Floor(Log2(number))) of the specified number.
    /// </summary>
    /// <remarks>Example: Log2(10) returns 3.</remarks>
    /// <param name="number">The number whose base 2 log is desired.</param>
    /// <returns>The base 2 log of the number greater than 0, or 0 when the number
    /// equals 0.</returns>
    public static byte Log2(this byte value) {
        return msbPos256[value | 1];
    }
    

    对于无符号的 32 位 int,以下将起作用

    private static byte[] DeBruijnLSBsSet = new byte[] {
        0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
        8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
    };
    public static uint Log2(this uint value) {
        value |= value >> 1;
        value |= value >> 2;
        value |= value >> 4;
        value |= value >> 8;
        return DeBruijnLSBsSet[unchecked((value | value >> 16) * 0x07c4acddu) >> 27];
    }
    

    这个网站是玩小把戏的好去处

    http://graphics.stanford.edu/~seander/bithacks.html

    它具有这些以及许多其他技术,可以实现您在问题中提出的要求。

    【讨论】:

    • 嗨!是否可以将此代码扩展到 64 位数字?
    • @Denis - 我没有 64 位版本,但是我想你可以使用上面的代码来做到这一点,如下所示:创建一个最重要的 uint您的值(uint)(value &gt;&gt; 32) 的 4 个字节。如果等于 0,则返回 64 位值的低 4 个字节的 Log2,否则返回 64 位值的高 4 个字节的 32 + Log2。
    • 感谢您的回答。看来,我找到了这段代码的 64 个版本:stackoverflow.com/a/3465395/1756750
    【解决方案2】:

    正如@hatchet 所说,有许多利用小型查找表的通用技巧。

    但是,还有一个值得注意的替代方案。如果您想要最快的实现并且使用低级语言,那么该指令也内置在几乎所有 ISA 中,并且几乎得到所有编译器的支持。请参阅 https://en.wikipedia.org/wiki/Find_first_set 并酌情使用编译器内在函数或内联汇编。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-27
      • 2019-04-23
      • 1970-01-01
      • 2018-03-17
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多