Ceiling of the Logarthim Base Two

Leo de Wit leo at philmds.UUCP
Fri Jul 1 18:16:09 AEST 1988


In article <10978 at sol.ARPA> crowl at cs.rochester.edu (Lawrence Crowl) writes:
  [introducory stuff for exponent calculating macro deleted]....

>#define CEILOG2_U( n ) ((n) > 0x40000000 ? 31 : (n) > 0x20000000 ? 30 : \
>(n) > 0x10000000 ? 29 : (n) > 0x08000000 ? 28 : (n) > 0x04000000 ? 27 : \
>(n) > 0x02000000 ? 26 : (n) > 0x01000000 ? 25 : (n) > 0x00800000 ? 24 : \
>(n) > 0x00400000 ? 23 : (n) > 0x00200000 ? 22 : (n) > 0x00100000 ? 21 : \
>(n) > 0x00080000 ? 20 : (n) > 0x00040000 ? 19 : (n) > 0x00020000 ? 18 : \
>(n) > 0x00010000 ? 17 : (n) > 0x00008000 ? 16 : (n) > 0x00004000 ? 15 : \
>(n) > 0x00002000 ? 14 : (n) > 0x00001000 ? 13 : (n) > 0x00000800 ? 12 : \
>(n) > 0x00000400 ? 11 : (n) > 0x00000200 ? 10 : (n) > 0x00000100 ?  9 : \
>(n) > 0x00000080 ?  8 : (n) > 0x00000040 ?  7 : (n) > 0x00000020 ?  6 : \
>(n) > 0x00000010 ?  5 : (n) > 0x00000008 ?  4 : (n) > 0x00000004 ?  3 : \
>(n) > 0x00000002 ?  2 : (n) > 0x00000001 ?  1 : (n) > 0x00000000 ?  0 : \
>abort( ) )

  [second symmetric solution for search up deleted]...

Let's take for granted (as the author does) that n is at most a simple
expression (an optimizer could keep it in a register for instance),
otherwise simply shifting should be preferred.

This macro is easily adapted for a binary search (in fact the 32 bit
integers scream for it 8-); note I used a somewhat different layout to
make things clearer for this macro (b.t.w. the 1<<xx will evaluate to a
constant at compile time).


#define CEILOG2_U( n ) (\
(n) > 1<<15 ? (n) > 1<<23 ? (n) > 1<<27 ? (n) > 1<<29 ? (n) > 1<<30 ? 31 : 30\
                                                      : (n) > 1<<28 ? 29 : 28\
                                        : (n) > 1<<25 ? (n) > 1<<26 ? 27 : 26\
                                                      : (n) > 1<<24 ? 25 : 24\
                          : (n) > 1<<19 ? (n) > 1<<21 ? (n) > 1<<22 ? 23 : 22\
                                                      : (n) > 1<<20 ? 21 : 20\
                                        : (n) > 1<<17 ? (n) > 1<<18 ? 19 : 18\
                                                      : (n) > 1<<16 ? 17 : 16\
            : (n) > 1<<7  ? (n) > 1<<11 ? (n) > 1<<13 ? (n) > 1<<14 ? 15 : 14\
                                                      : (n) > 1<<12 ? 13 : 12\
                                        : (n) > 1<<9  ? (n) > 1<<10 ? 11 : 10\
                                                      : (n) > 1<<8  ?  9 :  8\
                          : (n) > 1<<3  ? (n) > 1<<5  ? (n) > 1<<6  ?  7 :  6\
                                                      : (n) > 1<<4  ?  5 :  4\
                                        : (n) > 1<<1  ? (n) > 1<<2  ?  3 :  2\
                                                      : (n) > 1<<0  ?  1 :  0)

The average search is 5 steps, while the linear search averages to 16 steps.
Another approach is to assign the value to a float (double) and use the
exponent. This could even prove faster. For example:

#include <math.h>

int expo;

      frexp((double)n,&expo);

If frexp is builtin this just could be faster. Otherwise the bits of 
(double)n can be manipulated (non-portable).

Enjoy!

       Leo.



More information about the Comp.lang.c mailing list