最小位数代表给定的`int`?

时间:2014-01-17 16:47:22

标签: c++ algorithm bit-manipulation logarithm

在C ++中,找出存储给定int需要多少位的最快方法是什么?

我可以尝试将数字除以2次,但划分相当慢。有什么快捷方式吗?

编辑:非常感谢答案的人。当我说一个int我的帖子,我的意思是任何4字节int。例如,如果我存储30665,我希望得到15位。

9 个答案:

答案 0 :(得分:4)

在C ++ 20中,您只需要使用std::bit_width()或等同版本

return std::numeric_limits<T>::digits - std::countl_zero(x);

如果您使用的是较旧的C ++标准,请使用boost::multiprecision::msb(),它会自动映射到当前编译器的适当内在函数,例如__builtin_clz()_BitScanReverse() ...

return boost::multiprecision::msb(x);

答案 1 :(得分:3)

您可以逐步将值分解为一半,以便更快地缩小范围。

int bits_needed(uint32_t value)
{
    int bits = 0;
    if (value >= 0x10000)
    {
        bits += 16;
        value >>= 16;
    }
    if (value >= 0x100)
    {
        bits += 8;
        value >>= 8;
    }
    if (value >= 0x10)
    {
        bits += 4;
        value >>= 4;
    }
    if (value >= 0x4)
    {
        bits += 2;
        value >>= 2;
    }
    if (value >= 0x2)
    {
        bits += 1;
        value >>= 1;
    }
    return bits + value;
}

查看实际操作:http://ideone.com/1iH7hG

编辑抱歉,原始版本需要一个额外的期限。现在已经修好了。

编辑2 按照评论中的建议以循环形式。

int bits_needed(uint32_t value)
{
    int bits = 0;
    for (int bit_test = 16; bit_test > 0; bit_test >>= 1)
    {
        if (value >> bit_test != 0)
        {
            bits += bit_test;
            value >>= bit_test;
        }
    }
    return bits + value;
}

此算法为0的输入返回0,这意味着您根本不需要任何位来编码0的值。如果您更愿意返回1,只需将返回值更改为bits + 1

答案 2 :(得分:2)

使用比移动“更快”的算法无法执行此操作。

但您可以使用以下算法(包括<cmath>):

int bits_n(int x) {
    return (x != 0)
        ? std::ceil(std::log(x) / std::log(2))
        : 1;
}

对于大多数应用来说可能足够快。

在基数2中执行对数需要std::log(x) / std::log(2)(因为C和C ++ does not have a function的标准库都可以执行它。)

here你可以找到一个实例。

答案 3 :(得分:2)

查看着名的Bit Twiddling Hacks page,特别是counting bits上的部分。

供参考,这是Brian Kernighan的方法计算设置的位数

unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
  v &= v - 1; // clear the least significant bit set
}

答案 4 :(得分:2)

对于非零无符号整数类型,您可以使用gcc / clang以下之一

sizeof(unsigned)           - __builtin_clz(x)
sizeof(unsigned long)      - __builtin_clzl(x)
sizeof(unsigned long long) - __builtin_clzll(x)

对于MSVC ++上的32位和64位整数,您可以定义变量index来存储

的结果
_BitScanReverse(&index, x)
_BitScanReverse64(&index, x)

如果您的计算机支持,那些编译器包装器将委托给硬件指令,否则就会委托一些优化的bit-twiddling算法。您可以使用一些#ifdef来编写自己的半平台独立包装器。

Matthew Fioravante有一个相关的stdcxx-bitops GitHub repo作为floated to the std-proposals邮件列表,作为为C ++添加constexpr按位运算库的初步建议。如果标准化,那么会有类似std::clz()功能模板的功能,可以满足您的需求。

答案 5 :(得分:1)

让我们重新解释这个问题(无论如何对于无符号整数):我的整数的msb是否会下降?

(只是确定你知道为什么)

让我们在十进制中考虑这一点。存储号码需要多少位数?如果我写出了号码(因为计算机将用于任何号码),我所要做的就是计算数字,并报告最大数字的位置。

现在人们不会想二进制,所以你必须在十进制数字和二进制数字之间进行转换......除了计算机会在解析中为你做这些。函数的输入将是一个二进制数,所以你要做的就是找到msb的位置。

获得无符号整数的MSB的最快方法(不幸的是)不是超级便携式的。

What is the fastest/most efficient way to find the highest set bit (msb) in an integer in C?

进入寻找MSB的所有方法。长话短说,虽然C ++可能不会直接为你提供一个钩子,但大多数编译器都将它作为汇编命令内置。所以这将是最快的方式。

答案 6 :(得分:0)

可能最快的方式是使用预先填充的查找表。

const size_t bitsMap [] =
{
  0, // value 0 (0)
  1, // value 1 (1)
  2, // value 2 (10)
  2, // value 3 (11)
  3, // value 4 (100)
 // ...
};

您也可以使用数学方法(例如vector)在启动时计算此数组(或ceil(log2(n))或类似数据)。

您现在有一个数字n,您想知道需要多少位来表示。您只需使用n索引数组 - 存储的值就是位数。

int main()
{
  for (int i = 0; i < 256; ++i)
  {
    const size_t bits = bitsMap [i];
    cout << "The number " << i << " would take " << bits << " to represent."
  }
}

立即索引数组。我不知道你怎么会比这更快。

答案 7 :(得分:0)

int num = number;
int count_bit =0;
while (num) {
  num = num>>1;
  count++;
}
std::cout << num << " needs " << count << " bits" << std::endl;  

答案 8 :(得分:0)

首先初始化位= 0。然后循环,直到比特的平方等于数字。

    void bits(int x) 
    {
                int bit = 1;

                while(pow(2,bit) < x) 
                {
                     bit++;
                }
                printf("%d",bit);
    }

另一种方法:

 int bit = static_cast<int>(log2(x));