9

In C++, what's the fastest way to find out how many bits are needed to store a given int?

I can try dividing the number with 2 many times but divisions are pretty slow. Is there any fast way?

Edit:

Thanks a lot for the answers guys. When I say an int my post, I mean any 4-byte int. For example, if I store 30665, I want to get as a result 15 bits.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Luka
  • 1,761
  • 2
  • 19
  • 30
  • 5
    `ceil(log2(n))` is the easiest. – Mark Ransom Jan 17 '14 at 16:50
  • 3
    Have a look at http://graphics.stanford.edu/~seander/bithacks.html –  Jan 17 '14 at 16:50
  • 1
    ceil is slower than divisions... – Luka Jan 17 '14 at 16:50
  • @Luka that's why I made it a comment instead of an answer.\ – Mark Ransom Jan 17 '14 at 16:51
  • anyway, you solution is good but I want something faster – Luka Jan 17 '14 at 16:52
  • 1
    Division by two is one of the fastest things a circuit can do, if you use a (logical) right shift instead of integer division. –  Jan 17 '14 at 16:53
  • 1
    http://stackoverflow.com/questions/671815/what-is-the-fastest-most-efficient-way-to-find-the-highest-set-bit-msb-in-an-i – IdeaHat Jan 17 '14 at 16:53
  • @delnan all modern compilers will do bitshifts for all (constant) power of two integer divides. – IdeaHat Jan 17 '14 at 16:55
  • @MadScienceDreams And some not so modern ones. I was implying "division by two is *not* as slow as general integer division", though it's also important that one usually doesn't need to do that manually. (Note though that for signed types like `int`, the full story is a bit more complicated.) –  Jan 17 '14 at 17:00

9 Answers9

10

In C++20 you just need to use std::bit_width() or its equivalent

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

If you're on an older C++ standard then use boost::multiprecision::msb() which automatically maps to the appropriate intrinsic of the current compiler like __builtin_clz() or _BitScanReverse()... Or use #ifdef and manually switch the implementation depending on the current compiler

return boost::multiprecision::msb(x);               // Cross-platform

int index;
return _BitScanReverse(&index, n)) ? index + 1 : 1; // MSVC, ICC
return 32 - _lzcnt_u32(n);                          // ICC
return 32 - __builtin_clz(X));                      // GCC, Clang
phuclv
  • 37,963
  • 15
  • 156
  • 475
4

You can break the value progressively by halves to narrow it down faster.

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;
}

See it in action: http://ideone.com/1iH7hG

Edit: Sorry, the original version needed one additional term. It's fixed now.

Edit 2: In loop form as suggested in the comments.

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;
}

This algorithm returns 0 for an input of 0, meaning you don't need any bits at all to encode a value of 0. If you'd rather it return 1 instead, just change the return value to bits + 1.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
3

Take a look at the famous Bit Twiddling Hacks page, if particular the section on counting bits.

For reference, here's the Brian Kernighan way to count the number of bits set:

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
}
greybeard
  • 2,249
  • 8
  • 30
  • 66
Sean
  • 60,939
  • 11
  • 97
  • 136
  • Doesn't this have linear complexity? – Shoe Jan 17 '14 at 17:02
  • also, can you provide an example? – 4pie0 Jan 17 '14 at 17:03
  • 1
    @Jefffrey It's linear in the number of set bits, not in the number of total bits. But when it gets this low level and small (n <= 64), asymptotic complexity is not the most useful tool. –  Jan 17 '14 at 17:04
  • Where this kills you is the branching factor in the for loop. For each bit you are doing an increment, a comparison, and a branch, which will be (relatively) slow to other methods. – IdeaHat Jan 17 '14 at 17:13
  • works only if the number is from 0-255. if I have a number >= 256 random results appear – Luka Jan 17 '14 at 17:15
  • I posted this code sample as it was the shortest of the many different ways on the bit twiddling hacks page. If you follow the link you'll see there are lots of alternatives which don't use looping. – Sean Jan 17 '14 at 17:18
  • 2
    I think this is answering the **wrong question**. It's the number of bits set, not the total number of bits. – Mark Ransom Jan 17 '14 at 17:20
  • @MarkRansom - that may be true now. The questioner has editted the question since I posted the answer... – Sean Jan 17 '14 at 17:21
  • I read the question when it was originally posted, and it seemed pretty clear at the time. – Mark Ransom Jan 17 '14 at 17:23
  • that's why I asked for example – 4pie0 Jan 17 '14 at 17:23
  • 1
    @Sean Quick edits by the original poster aren't recorded, but I'm pretty sure the question always was "how many bits are needed to store an int" which was already pretty clear IMHO (and at least one early answer interpreted it correctly, the `ceil(log2(x))` variant). –  Jan 17 '14 at 17:25
3

For non-zero unsigned integral types, you can use for gcc/clang one of the following

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

For and for 32-bit and 64-bit integers on MSVC++ you can define a variable index to store the result of

_BitScanReverse(&index, x)
_BitScanReverse64(&index, x)

Those compiler wrappers will delegate to hardware instructions if your computer supports it, or some optimized bit-twiddling algorithm otherwise. You can write your own semi-platform independent wrapper around it using some #ifdefs.

There is a related stdcxx-bitops GitHub repo by Matthew Fioravante that was floated to the std-proposals mailinglist as a preliminary proposal to add a constexpr bitwise operations library for C++. If and when that gets standardized, there will be something like a std::clz() function template that does what you are looking for.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
2

You can't perform this with an algorithm that is "faster" than shifting.

But you can use the following algorithm (including <cmath>):

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

which is likely fast enough for most applications.

The std::log(x) / std::log(2) is required to perform a logarithm in base 2 (because the standard library of both C and C++ does not have a function to perform it).

And here you can find a live example.

Community
  • 1
  • 1
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • 1
    and calculating the log2(x) is faster than shifting? – 4pie0 Jan 17 '14 at 16:57
  • @piotruś, it depends on the implementation. – Shoe Jan 17 '14 at 17:01
  • 1
    I doubt this can be faster, the question is about something faster than shifting – 4pie0 Jan 17 '14 at 17:02
  • @piotruś, the only operation faster than shifting is a non-op. – Shoe Jan 17 '14 at 17:03
  • 1
    that is why I don't see this as an answer. The question is about something faster than shifting – 4pie0 Jan 17 '14 at 17:05
  • 1
    Since it's required to compute a floating point number that accurately approximates the real logarithm of `x , I doubt it can possibly be faster. Unless the compiler intercepts this *specific* pattern and replaces it with a completely different algorithm, of course. –  Jan 17 '14 at 17:06
  • @piotruś, you are right. I've fixed the answer, hopefully. :) – Shoe Jan 17 '14 at 17:07
1

Let's rephrase the question (for unsigned integers anyway): where does the MSB of my integer fall?

(just making sure you know why)

Let's think about this in decimal for a second. How many digits do you need to store a number? If I have the number written out (as the computer will for any number) all I have to do is count the digits, and report the position of the largest digit.

Now people don't think in binary, so you gotta translate between your decimal digit and your binary digit... except the computer will do that for you in the parse. The input to your function will be a binary number, so all you have to do is find the location of the MSB.

The fastest way to get the MSB of an unsigned integer is (unfortunately) not super portable.

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

Goes into all the ways to find the MSB. Long story short, while C++ may not give you a hook for it directly, most compilers have this built in as a assembly command. So that would be the fastest way.

phuclv
  • 37,963
  • 15
  • 156
  • 475
IdeaHat
  • 7,641
  • 1
  • 22
  • 53
0

Likely the fastest way is by using a prepopulated lookup table.

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

You could also populate this array (or vector or similar) by computing it at startup using mathematical means, such as ceil(log2(n)).

You now have a number n which you want to know how many bits will be needed to represent. You simply index the array using n -- the value storesd there is the number of bits.

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

Indexing the array is immediate. I don't see how you'll get any faster than that.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 2
    This is only feasible when the range of `n` is reasonably small. I don't see such a restriction in the question. –  Jan 17 '14 at 17:03
  • @delnan: Depends on what "reasonably small" means. It could be a `uint64_t`. If the speed of this is so important, they can invest in an additional RAM stick to make this work. – John Dibling Jan 17 '14 at 17:03
  • 1
    @JohnDibling This could also require a memory lookup, which is slower than some built in MSB operations – IdeaHat Jan 17 '14 at 17:07
  • Huh? If `n` can be any 64 bit integer, you'd need 2^64 table entries. You can't even address this much memory on today's architectures ("64 bit" CPUs only use 48 bits for addressing). That's 16 million terabytes of RAM. That's simply not possible, period. For 32 bit it's physically possible, but still completely stupid: There are *far* better uses for 4 GiB of RAM, and with RAM being much slower than today's CPUs you won't gain any performance. –  Jan 17 '14 at 17:11
  • but the idea is very nice, if only RAM could have been faster... ;p – 4pie0 Jan 17 '14 at 17:14
  • @piotruś You mean "completely free and taking absolutely no space"? –  Jan 17 '14 at 17:17
  • You could well create the table for a single byte (256 entries) and then apply several lookups for larger numbers. That’s a common technique. – Konrad Rudolph Jan 17 '14 at 17:19
  • idea is nice, maybe this can be adjusted somehow, lookup several times or something similar... – 4pie0 Jan 17 '14 at 17:22
  • @piotruś: There's a similar implementation [here](http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable), but it involves 3 shifts in one case. The cast in the second case looks interesting, if platform-specific. – John Dibling Jan 17 '14 at 17:26
0
int num = number;
int count_bit =0;
while (num) {
  num = num>>1;
  count++;
}
std::cout << num << " needs " << count << " bits" << std::endl;  
Daniele
  • 821
  • 7
  • 18
-1

At first Initialize bit=0. Then looping until the square of bit equal to the number.

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

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

Another method :

 int bit = static_cast<int>(log2(x));
rashedcs
  • 3,588
  • 2
  • 39
  • 40
  • 1
    This question is about "the fastest way", yet `pow(2,bit)` is one of the worst ways to calculate powers of 2, and looping over powers of 2 like that is even worse because `pow(2, 1)` is calculated `bit!` times – phuclv Mar 24 '20 at 16:32