[comp.lang.c] Programming gems

peter@ficc.uu.net (Peter da Silva) (01/20/89)

In article <3891@ece-csc.UUCP>, jnh@ece-csc.UUCP (Joseph Nathan Hall) writes:
> In a similar vein, what interesting bit-reversal algorithms are there
> (distinct from the problem of COUNTING bit-reversed)?

How about a good algorithm for reversing bits? (the quickest I can think
off offhand involves table lookup).
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.   `-_-'
Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net.                 'U`
Opinions may not represent the policies of FICC or the Xenix Support group.

hoey@ai.etl.army.mil (Dan Hoey) (01/25/89)

Several bit permutations can be achieved by shifting a subset of the bits of an
N-bit number O(N) times.  Most of the interesting ones are characterized by
moving bit I to bit R(I) where R is a function that permutes the bits of its
argument and complements some subset of those bits.  Common examples of such
permutations are reversing the bits, performing a perfect shuffle on the bits,
and--approximately--a couple of the permutations used in the DES encryption
standard.  For reversing the bits of a 32-bit number, the following code
suffices.

long BitRev(n) register long n;{

  n = ((n >>  1) & 0x55555555) | ((n <<  1) & 0xaaaaaaaa);
  n = ((n >>  2) & 0x33333333) | ((n <<  2) & 0xcccccccc);
  n = ((n >>  4) & 0x0f0f0f0f) | ((n <<  4) & 0xf0f0f0f0);
  n = ((n >>  8) & 0x00ff00ff) | ((n <<  8) & 0xff00ff00);
  n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);

  return n;
}

mouse@mcgill-vision.UUCP (der Mouse) (02/01/89)

In article <2818@ficc.uu.net>, peter@ficc.uu.net (Peter da Silva) writes:
> In article <3891@ece-csc.UUCP>, jnh@ece-csc.UUCP (Joseph Nathan Hall) writes:
>> In a similar vein, what interesting bit-reversal algorithms are
>> there (distinct from the problem of COUNTING bit-reversed)?
> How about a good algorithm for reversing bits? (the quickest I can
> think off offhand involves table lookup).

This becomes an interesting problem when lots of bits are involved, as
in a bitmap screen.  There's an easy divide-and-conquer algorithm for
reversing a bitmap screen when the width (or height, if you want to
flip it vertically) is a power of two, requiring a second copy for use
as a mask.  (With sufficiently intelligent rasterop (aka bitblt)
algorithms, the extra space needed is only one row, because all rows of
the mask are always identical.)  Here's the essence of the algorithm,
applied to reversing an unsigned int (assumed to be 32 bits):

unsigned int reverseit(unsigned int value)
{
 unsigned int mask;
 int i;

 i = 32;
 mask = ~0;
 while (i > 1)
  { mask ^= mask << i;
    value ^= (value & mask) >> i;
    value ^= (value << i) & mask;
    value ^= (value & mask) >> i;
    i = i / 2;
  }
 return(value);
}

Of course, it's silly to use this for an int, but for a bitmap, it
makes a good deal more sense.  It becomes a more interesting problem
when the size is not a power of two.  I played with the algorithm and
came up with a variant that works for non-powers-of-two.  Since I've
never seen such a variant even referred to anywhere, here it is....
Again, it's applied to reversing an int, but this time the number of
bits is passed in as a parameter.  It should be clear how to extend
this to the case when value and mask are really bitmap arrays (and
width_in_bits is somewhat larger).  I have a program that flips a Sun
screen using this algorithm, so it definitely works.

unsigned int reverse(unsigned int value, int width_in_bits)
{
 unsigned int mask;
 int w;
 int w2;
 int lastodd;

 w = width_in_bits;
 mask = (1UL << w) - 1UL;
 /* the above assumes w is less than the number of bits in mask,
    or that << returns 0 when w equals that number. */
 lastodd = 0;
 while (w > 1)
  { w2 = w - (w / 2);
    mask &= mask << w2;
    mask |= mask >> (w+lastodd);
    value ^= mask & (value << w2);
    value ^= (mask & value) >> w2;
    value ^= mask & (value << w2);
    lastodd = w & 1;
    w -= w2;
  }
 return(value);
}

Is this new?  Surely not....but it isn't too widely known (translation:
I never heard of it anywhere :-).

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu