Minimum bits required to represent a natural number

Asked

Viewed 2,819 times

5

What is the most performative way to find the minimum number of bits needed to represent a natural number (i.e. no signal) in Javascript? There is a way to do without using loops?

The code below for example works for every integer between 0 and 2^30 - 1 (infinite loop if it is larger than that):

var x = 9001;
var bits = 1;
while ( x >= (1 << bits) )
    bits++;

And this one works until 2^53 (the largest representable integer guaranteed without loss of precision) and somewhat beyond:

var x = 9001;
var bits = 1;
var limite = 2;
while ( x >= limite ) {
    bits++;
    limite *= 2;
}

But they both use loops, basically asking: does it fit in 1 bit? does it fit in 2 bits? does it fit in 3 bits? etc. I was curious to know if there is a better way to do this.

Note: I’m only interested in know how many bits are needed, not in actually doing that representation. Even because Javascript does not use int, long, unsigned int, etc - and yes double for everything... (and when you use, does not expose to the programmer)

  • I would sound even stupider than I look if I asked why this question?

  • @Brunoaugusto Originally, I wanted to store a bit mask and a unique identifier in a single Number. For this I needed to know if the identifier (variable) "fits" in the space that remains beyond the mask (fixed). As I wrote the question, I realized that saying whether or not it fits is easy - I just subtract from 53 available bits the size of the mask, and see if the identifier is between zero and the largest number that fits in that space. But I remained curious to know if there is a way to determine the minimum number of bits needed, given a number, so I submitted the question anyway.

  • In the general case, calculating the logarithm of a number - even approximate - is complicated, but in binary it is easy: just count the bits to the right of the last bit set (inclusive). But can you do this with a simple operation? I don’t know, and I thought maybe someone knew a way...

1 answer

4

First, the mathematical aspect:

A positive and integer number n has b bits when 2b-1 < n < 2b-1.

This means that as long as my integer does not exceed the value of a given power of 2, the amount of bits needed to express that integer is the basis of that power minus one. Examples:

Decimal   Próxima potência de 2  Bitmap      Bits necessários
511       512  (2^10)            111111111   9
967       1024 (2^11)            1111000111  10

So to calculate how many bits b are required to express a number n, we can use logarithms. So:

bwhole = int(log2(n)) + 1

This formula can be divided into three parts:

  • log2(n) means the base 2 logarithm of N, which is the exponent to which 2 is raised to reach N. Javascript does not support logarithm calculations on a basis other than 10, so we need to divide Math.log(n) for Math.log(2).
  • Int(x) is the entire part of x. In Javascript, the equivalent function is Math.floor().
  • +1 plays the exponent to the next power of 2, to compensate for the last position of its number in binary expression.

A way to express this formula in JavaScript would be:

function numBits(numero)
{
    return Math.floor( Math.log(numero) / Math.log(2) ) + 1;
}

I prepared a Jsfiddle where you can test the performance of each method. Assume methods 1 and 2 as in your original question, and 3 as the one in this answer.

My results for a cycle of 1 to 50,000,000 were:

Método 1: 3244 ms
Método 2: 2103 ms
Método 3:  181 ms
(Browser: Google Chrome Version 36.0.1985.125)

Método 1: 1564 ms
Método 2: 2434 ms
Método 3: 2518 ms
(Browser: Internet Explorer 11)

Sources:

  • 2

    It should be noted that this solution (no cycles) is not necessarily more performant than a solution with cycles: this will depend on how the JS interpreter will optimize the cycles and how the functions of the Math are implemented.

  • @Miguelventura Yeah, I also thought about it. Logarithm crossed my mind, but I dismissed thinking about the performance. In fact, he’s slower (for relatively small numbers, at least). Anyway, +1 for the mathematical aspect.

  • By the way, I thought the solution with cycles would be better for small numbers, and the better logarithm for large numbers, but it’s not what I observed. Probably, the calculation of the logarithm is not even done in constant time...

  • P.S. In fact, Chrome is faster for very large numbers! Probably their log algorithm is better

  • That’s right - curious, isn’t it? I got the urge to test on other browsers...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.