仅用1位设置检测整数的优化

时间:2015-11-04 07:50:18

标签: c++ optimization

我有一个功能:

inline uint32_t ShiftOf(uint32_t v)
{
    for (uint32_t s = 0; s < 32; ++s)
    {
        if (v == 1 << s)
            return s;
    }
    return -1;
}

有没有办法优化它?

5 个答案:

答案 0 :(得分:24)

如果您只需要检测是否设置了一位,而不是哪一位,您可以optimize this significantly

int is_power_of_two(uint32_t v) {
    return v && !(v & (v - 1));
}

如果您需要实际计算设置了哪个位,而不仅仅是设置了一个位,那么您有a plethora of options(或者您只是在验证它的功能之后作弊并使用C99的log2函数两个并投下结果)。

简答:书签Bit Twiddling Hacks。它很方便。

答案 1 :(得分:22)

有一些方法可以优化功能。

使用按位运算符进行优化:

filter["CY_FOLDER_ID"] = "\"" + testSetFolderPath + "\"";

使用编译器内在函数进行优化:

inline uint32_t ShiftOf(uint32_t v)
{
    uint32_t s =
        (bool)(v & 0xFFFF0000) * 16 +
        (bool)(v & 0xFF00FF00) * 8 +
        (bool)(v & 0xF0F0F0F0) * 4 +
        (bool)(v & 0xCCCCCCCC) * 2 +
        (bool)(v & 0xAAAAAAAA);
    return v == 1 << s ? s : -1;
}

使用哈希表进行优化:

inline uint32_t ShiftOf(uint32_t v)
{
#if defined(_MSC_VER)
    DWORD s = 0;
    if (!_BitScanForward(&s, v))
        return -1;
#elif defined(__GNUC__)
    uint32_t s = __builtin_ctz(v);
#else
#    error This platform is unsupported!
#endif
    return v == 1 << s ? s : -1;
}

答案 2 :(得分:8)

我不确定但你可以展开循环:

inline uint32_t ShiftOf(uint32_t v)
{
    switch (v)
    {
    case 0x00000001: return 0;
    case 0x00000002: return 1;
    case 0x00000004: return 2;
    case 0x00000008: return 3;
    case 0x00000010: return 4;
    case 0x00000020: return 5;
    case 0x00000040: return 6;
    case 0x00000080: return 7;
    case 0x00000100: return 8;
    case 0x00000200: return 9;
    case 0x00000400: return 10;
    case 0x00000800: return 11;
    case 0x00001000: return 12;
    case 0x00002000: return 13;
    case 0x00004000: return 14;
    case 0x00008000: return 15;
    case 0x00010000: return 16;
    case 0x00020000: return 17;
    case 0x00040000: return 18;
    case 0x00080000: return 19;
    case 0x00100000: return 20;
    case 0x00200000: return 21;
    case 0x00400000: return 22;
    case 0x00800000: return 23;
    case 0x01000000: return 24;
    case 0x02000000: return 25;
    case 0x04000000: return 26;
    case 0x08000000: return 27;
    case 0x10000000: return 28;
    case 0x20000000: return 29;
    case 0x40000000: return 30;
    case 0x80000000: return 31;
    default: return -1;
    }
}

答案 3 :(得分:4)

如果你想要最大的速度(以更少的代码可移植性为代价),现代处理器已经为此优化了指令,这些指令通过不同的内部函数名称&#34;取决于编译器。

此操作的最常见名称是BSR(位扫描反转=查找最高位的索引)。在MSVC下,它可以使用内部函数_BitScanReverse,resp生成。 _BitScanReverse64 (需要额外的掩码参数)

以下网页上的更多参考资料: https://en.wikipedia.org/wiki/Find_first_set

答案 4 :(得分:1)

您可以计算设置的位数,看看它是否为1。

查阅Fast Bit Counting页面,您将找到许多不同的例程来快速计算位数。

最快 4b。 Precompute-16bit (虽然这是在C中):

static char bits_in_16bits [0x1u << 16];

int bitcount (unsigned int n)  {
   // works only for 32-bit ints

   return bits_in_16bits [n         & 0xffffu]
       +  bits_in_16bits [(n >> 16) & 0xffffu];
}
  

Precompute_16bit是Precompute_8bit的变体,其中一个数组bits_in_16bits []存储连续16位数(短路)中的1位数。

但是这个版本需要相当多的内存。您可以尝试各种版本以找到适合您需求的版本。