Simplest way is to place the number into a single variable large enough to store the biggest number you'll be dealing with, then left-shift (and count) until the left-most bit (MSB) is not zero, then subtract that count from the size of the variable.
Something like:
int bits(unsigned int val) { // Should work with any size integer.
unsigned int maxbits = sizeof(val) * 8;
unsigned int mask = 1 << maxbits-1; // Make sure this is the same size as val
unsigned int count = 0;
while (((val & mask) == 0) && (count < maxbits)) {
val <<= 1;
count++;
}
return maxbits - count;
}
What majenko said, except that there is a simplification (assuming that all of the numbers are positive):
Right shift and count the number of shifts until the result is zero.
If the number could be negative, I don't think that my method or majenko's method works. In that case, I think that I would want to treat (sign bit == 1, all other bits == 0) as a special case, and otherwise take the absolute value. Follow this up with my method or the one from majenko.
Alternative that doesn't modify the value (if that matters...):
uint32_t testval = 1337;
uint8_t size = 32; // Set to maximum width of container variable
while (size) {
size--;
if (testval & (1 << size)) break;
}
Serial.println("Value %lu requires %u bits\n", testval, size + 1);
This code will never return "requires 0 bits" due to the size + 1 and the structure of the loop. If you want that to be a valid option, you'll need to tweak the loop or special-case it with something like:
// Intentionally overflow this unsigned integer value
if (testval == 0) size = (0 - 1);
Serial.println("Value %lu requires %u bits\n", testval, size + 1);
Thank you all for the replies so far. I ended up figuring this out myself in the course of trying to to the rest of what I'm trying to do... which is reversing the bit order of any arbitrary number (up to 64 bits long).
Here's what I have so far, but the voices in my head are telling me what I have is clumsy and can be done easier, but I'm not seeing it. Any input here would be appreciated!
uint64_t bitreverse (uint64_t value)
{
uint8_t bits = 0;
uint8_t x;
uint64_t tmp = 1;
while (value / tmp) {
bits++;
tmp <<= 1;
}
tmp = 0;
x = bits;
while (bits--) {
// put the bits into the high end...
tmp |= (value & _BV(bits)) ? _BV(x) : 0;
// ...and shift them down to the low end
tmp >>= 1;
}
return tmp; // return value bit-reversed
}
I would be wary of using this, since "an arbitrary number of bits" may not be the native word length of the value you want to reverse. (That is, are you sure the value's real MSB will always be set to 1?) What's the application context of this function?
It's easy to reverse a 64-bit number, or a modulo-8-bit number, or an arbitrary-length number ... but it's harder to guess the appropriate word length without knowing what the value's max can (or will or should) be.
Krupski:
I need a simple algorithm to tell me how many bits any particular number needs.
For example, if I send the function the value "61" (decimal), I want it to return "6" (because you need 6 bits to handle up to 63).
Likewise, if I send the function "1000" decimal, I want it to return "10" (decimal).
Others seem to think you want to count the bits in any given number. I think you want fo find out how many bits it requires to store a number.
I am limiting my method to unsigned numbers, long or shorter.
void setup() {
Serial.begin(115200);
for (int i = 0; i < 1024; i++) {
Serial.print ( i );
Serial.print(" ");
Serial.println(numBits(i));
}
for (unsigned long i = 0xfffffff0; i <= 0xfffffffe; i++) {
Serial.print ( i );
Serial.print(" ");
Serial.println(numBits(i));
}
}
void loop() {
// put your main code here, to run repeatedly:
}
byte numBits(unsigned long testNum) {
byte i;
unsigned long val = 1;
for( i = 1; i < 32 ; (i++)) {
val = val << 1;
if (val > testNum) {
return i;
}
}
return i;
}
lar3ry:
Others seem to think you want to count the bits in any given number. I think you want fo find out how many bits it requires to store a number.
How do those two things differ exactly?
My concern is, with an input of "1", what is the correct output?
1?
128?
32768?
2.147M?
9.22e18?
They differ in the most fundamental way.
If an unsigned byte, int, or long holds a value of 128, it will contain a single bit that is set to 1.
That same unsigned byte, int, or long requires 8 bits to hold the value of 128.
The OP said
I need a simple algorithm to tell me how many bits any particular number needs.
So, 128 requires 8 bits to hold the value. The OP did not ask for a method to tell him how many bits are set to 1.
Clearly, 128 requires 8 bits to represent that number. One of them is a 1, and seven of them are 0s.
lar3ry:
Others seem to think you want to count the bits in any given number. I think you want fo find out how many bits it requires to store a number.
How do those two things differ exactly?
My concern is, with an input of "1", what is the correct output?
1?
128?
32768?
2.147M?
9.22e18?
My sense of the problem seems to coincide with this.
To my way of thinking the number of bits in a number is irrelevant apart from as a code for the value of the number. In Arduino programming what matters is the type of the variable in which the number is stored. That is what defines the number of bits. Consider, for example, the different representation of -7 in an INT and in a LONG.
If there is some need to reverse a number the logic should be designed at the number level, not at the bit level.