3

Suppose I have an increasing sequence of unsigned integers C[i]. As they increase, it's likely that they will occupy increasingly many bits. I'm looking for an efficient conditional, based purely on two consecutive elements of the sequence C[i] and C[i+1] (past and future ones are not observable), that will evaluate to true either exactly or approximately once for every time the number of bits required increases.

An obvious (but slow) choice of conditional is:

if (ceil(log(C[i+1])) > ceil(log(C[i]))) ...

and likewise anything that computes the number of leading zero bits using special cpu opcodes (much better but still not great).

I suspect there may be a nice solution involving an expression using just bitwise or and bitwise and on the values C[i+1] and C[i]. Any thoughts?

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • possible duplicate of [Find most significant bit (left-most) that is set in a bit array](http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array) – kennytm Dec 10 '10 at 17:53
  • 1
    Please do not flag this as a duplicate! I'm asking about a problem that is less general and possibly has a better solution. – R.. GitHub STOP HELPING ICE Dec 10 '10 at 17:55

7 Answers7

16

Suppose your two numbers are x and y. If they have the same high order bit, then x^y is less than both x and y. Otherwise, it is higher than one of the two.

So

v = x^y
if (v > x || v > y) { ...one more bit... }
Keith Randall
  • 22,985
  • 2
  • 35
  • 54
  • 3
    Excellent! And since he already knows that `C[i+1]` > `C[i]`, then `if ((C[i+1] ^ C[i]) > C[i]) { /* number of bits has changed */ }` – Jim Mischel Dec 10 '10 at 18:24
  • Yep, you can get rid of 1 comparison that way. – Keith Randall Dec 10 '10 at 18:29
  • +1 and check. This is exactly what I was looking for, but I hadn't had time to think out the logic yet. It's much more efficient than all the other proposals which are essentially the same as the naive solution I wrote in the question. – R.. GitHub STOP HELPING ICE Dec 10 '10 at 19:24
2

I think you just need clz(C[i+1]) < clz(C[i]) where clz is a function which returns the number of leading zeroes ("count leading zeroes"). Some CPU families have an instruction for this (which may be available as an instrinsic). If not then you have to roll your own (it typically only takes a few instructions) - see Hacker's Delight.

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • I agree this can work (I just wrote it more abstractly with `ceil` and `log`), but I believe (especially if you relax the requirement from exactly when the bit size increases to just once-per-increase) that it can be done more efficiently. – R.. GitHub STOP HELPING ICE Dec 10 '10 at 17:58
  • How much more efficient than one instruction can you get ? (OK, OK, three instructions.) – Paul R Dec 10 '10 at 17:59
  • 1
    How do you implement `clz` in just a few instructions without a native instruction? The best I've found is in my solution, though the lsb can be found in just a few instructions using multiplication as mentioned in another SO question. – jonderry Dec 10 '10 at 18:17
  • Well, I deleted my count-leading-zeros solution (leaving just my power of 2 threshold solution) since Keith's solution is better than counting leading zeros for short sequences. Still, I'm curious if you know a better way to compute the index of the msb than the standard O(lg w) solution, which is still here in aix's solution. – jonderry Dec 10 '10 at 18:44
  • Just because `clz` is one instruction doesn't mean it's fast. I've seen more complicated asm that's faster on many x86 cpus... – R.. GitHub STOP HELPING ICE Dec 10 '10 at 19:21
0

The number of bits goes up when the value is about overflow a power of two. A simple test is then, is the value equal to a power of two, minus 1? This can be accomplished by asking:

if  ((C[i] & (C[i]+1))==0) ...
Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
  • There's no intention to commute them. If C[i] is about to overflow, and C[i+1] is larger, you need more bits for C[i+1]. You don't have to look at C[i+1] to decide that. – Ira Baxter Dec 10 '10 at 20:26
0

Given (I believe this comes from Hacker's Delight):

int hibit(unsigned int n) {
    n |= (n >>  1);
    n |= (n >>  2);
    n |= (n >>  4);
    n |= (n >>  8);
    n |= (n >> 16);
    return n - (n >> 1);
}

Your conditional is simply hibit(C[i]) != hibit(C[i+1]).

NPE
  • 486,780
  • 108
  • 951
  • 1,012
0

BSR - Bit Scan Reverse (386+)

    Usage:  BSR     dest,src
    Modifies flags: ZF

    Scans source operand for first bit set.  Sets ZF if a bit is found
    set and loads the destination with an index to first set bit.  Clears
    ZF is no bits are found set.  BSF scans forward across bit pattern
    (0-n) while BSR scans in reverse (n-0).

                             Clocks                 Size
    Operands         808x  286   386   486          Bytes

    reg,reg           -     -   10+3n  6-103          3
    reg,mem           -     -   10+3n  7-104         3-7
    reg32,reg32       -     -   10+3n  6-103         3-7
    reg32,mem32       -     -   10+3n  7-104         3-7

You need two of these (on C[i] and C[i]+1) and a compare.

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
0

Keith Randall's solution is good, but you can save one xor instruction by using the following code which processes the entire sequence in O(w + n) instructions, where w is the number of bits in a word, and n is the number of elements in the sequence. If the sequence is long, most iterations will only involve one comparison, avoiding one xor instruction.

This is accomplished by tracking the highest power of two that has been reached as follows:

t = 1; // original setting

if (c[i + 1] >= t) {
  do {
    t <<= 1;
  } while (c[i + 1] >= t); // watch for overflow
  ... // conditional code here
}
jonderry
  • 23,013
  • 32
  • 104
  • 171
  • I note your solution is a slight variation of mine. I also note that R. dinged mine (unreasonably IMHO) but did not ding yours. – Ira Baxter Dec 27 '10 at 17:03
-1

The number of bits goes up when the value is about to overflow a power of two. A simple test is then:

 while (C[i] >= (1<<number_of_bits)) then number_of_bits++;

If you want it even faster:

int number_of_bits = 1;
int  two_to_number_of_bits = 1<<number_of_bits ;


... your code ....

while ( C[i]>=two_to_number_of_bits )
   { number_of_bits++; 
     two_to_number_of_bits = 1<<number_of_bits ;
   }
Ira Baxter
  • 93,541
  • 22
  • 172
  • 341