Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: How can you get the number of a bit which is set in a bitboard ?

Author: Robert Hyatt

Date: 20:37:25 08/19/99

Go up one level in this thread


On August 19, 1999 at 21:19:51, Dann Corbit wrote:


that is well-known.  However, FirstOne() is used a lot, and without a
BSF/BSR (which is way faster than the code below) the table-lookup was
faster on every machine I tested it on.  The 4 array probes generally
get cache hits on reasonable hardware...

When I first wrote crafty, I (and several others) tried all sorts of
approaches.  Another interesting one is population count.  I use a
simple loop as I only use this on very sparsely populated bitmaps.  But
there are some amazingly clever approaches dealing with shift/add and a
divide at the end.  But none (for crafty) are faster than the simple loop
I now use...




>On August 19, 1999 at 21:02:15, Robert Hyatt wrote:
>>Those are the easy ones..  he is trying to find the number of the bit that
>>is set (ie the FirstOne()/LastOne() functions in Crafty).  That is harder..
>Oh.  High bit is easy.  Here are some algorithms for finding the most
>significant bit.  If you have long long or __int64 most of them are easily
>converted to other types:
>/***********************************************/
>/* Locate the postion of the highest bit set.  */
>/* A binary search is used.  The result is an  */
>/* approximation of log2(n) [the integer part] */
>/***********************************************/
>int             ilog2(unsigned long n)
>{
>    int             i = (-1);
>
>    /* Is there a bit on in the high word? */
>    /* Else, all the high bits are already zero. */
>    if (n & 0xffff0000) {
>        i += 16;                /* Update our search position */
>        n >>= 16;               /* Shift out lower (irrelevant) bits */
>    }
>    /* Is there a bit on in the high byte of the current word? */
>    /* Else, all the high bits are already zero. */
>    if (n & 0xff00) {
>        i += 8;                 /* Update our search position */
>        n >>= 8;                /* Shift out lower (irrelevant) bits */
>    }
>    /* Is there a bit on in the current nybble? */
>    /* Else, all the high bits are already zero. */
>    if (n & 0xf0) {
>        i += 4;                 /* Update our search position */
>        n >>= 4;                /* Shift out lower (irrelevant) bits */
>    }
>    /* Is there a bit on in the high 2 bits of the current nybble? */
>    /* 0xc is 1100 in binary... */
>    /* Else, all the high bits are already zero. */
>    if (n & 0xc) {
>        i += 2;                 /* Update our search position */
>        n >>= 2;                /* Shift out lower (irrelevant) bits */
>    }
>    /* Is the 2nd bit on? [ 0x2 is 0010 in binary...] */
>    /* Else, all the 2nd bit is already zero. */
>    if (n & 0x2) {
>        i++;                    /* Update our search position */
>        n >>= 1;                /* Shift out lower (irrelevant) bit */
>    }
>    /* Is the lowest bit set? */
>    if (n)
>        i++;                    /* Update our search position */
>    return i;
>}
>/*
>** From: <bousek@$smtpg.compsys.com$>
>** Subject: Re: Is there a faster way to find the highest bit set in a 32 bit
>integer? [Includes C code listing]
>** Newsgroups: comp.graphics.algorithms
>** References: <01bc3fac$69b314c0$ca61e426@DCorbit.solutionsiq.com>
>** Organization: TDS Telecom - Madison, WI
>** Message-ID: <01bc405b$2c1c8740$ca61e426@DCorbit.solutionsiq.com>
>** X-Newsreader: Microsoft Internet News 4.70.1155
>** MIME-Version: 1.0
>** Content-Type: text/plain; charset=ISO-8859-1
>** Content-Transfer-Encoding: 7bit
>**
>** "Dann Corbit" <dcorbit@solutionsiq.com> wrote:
>** <snip>
>** hey Dann:
>** you could modify your routine something like this (although i would tend to
>** put this type of routine in assembler)...
>*/
>int            qlog2(unsigned long n)
>{
>    register int    i = (n & 0xffff0000) ? 16 : 0;
>    if ((n >>= i) & 0xff00)
>        i |= 8, n >>= 8;
>    if (n & 0xf0)
>        i |= 4, n >>= 4;
>    if (n & 0xc)
>        i |= 2, n >>= 2;
>    return (i | (n >> 1));
>}
>int             klog2(unsigned long n)
>{
>    register int    p = 16,
>                    i = 0;
>    do {
>        unsigned long   t = n >> p;
>        if (t)
>            n = t, i |= p;
>    } while (p >>= 1);
>    return i;
>}
>#include <math.h>
>/*
> * FROM: steve@tangled-web.compulink.co.uk
> * This is the fully portable version, which uses
> * the 'frexp' function to get the mantissa and
> * exponent of a number.
> */
>int slog2( unsigned long value )
>{
>   int      exponent ;
>   double   d_val = (double)value ;
>   double   mantissa = frexp ( d_val, &exponent ) ;
>   return exponent - 1 ;
>}
>
>/*
> * FROM: steve@tangled-web.compulink.co.uk
> * This is the rather less portable version, which
> * requires you to know how doubles are stored
> * in memory, and the location and bias of the
> * exponent for such numbers.
> * This example is for doubles ( 64 bits )
> * on Intel hardware - YMMV.
> */
>/* CHANGED FROM DOUBLE TO FLOAT --
>#define MP(x)  ((long int *)&d_val)[x]
>int tlog2( unsigned long value )
>{
>   double d_val = (double)value ;
>   return (int)( MP(1) >> 20 & 0x7ff ) - 0x3ff ;
>}
>*/
>#define MP(x)  ((long int *)&d_val)[x]
>int tlog2( unsigned long value )
>{
>   float d_val = (float)value ;
>   return (int)( MP(0) >> 23 & 0xff ) - 0x7f ;
>}
>
>/*
>From:   Robert E. Minsk[SMTP:egbert@spimageworks.com]
>Sent:   Saturday, April 12, 1997 9:44 PM
>To:     Dann Corbit
>Subject:        Is there a faster way to find the highest bit set in a 32 bit
>integer? [Includes C code listing]
>
>  I did not see the original post but why don't you build a table of the
>highest bit set in a byte and then check each byte.  For example.
>*/
>static unsigned char hiBitSetTab[] = {
>    0, 1, 2, 2, 3, 3, 3, 3,
>    4, 4, 4, 4, 4, 4, 4, 4,
>    5, 5, 5, 5, 5, 5, 5, 5,
>    5, 5, 5, 5, 5, 5, 5, 5,
>    6, 6, 6, 6, 6, 6, 6, 6,
>    6, 6, 6, 6, 6, 6, 6, 6,
>    6, 6, 6, 6, 6, 6, 6, 6,
>    6, 6, 6, 6, 6, 6, 6, 6,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7,
>    7, 7, 7, 7, 7, 7, 7, 7
>};
>
>/* On my machine unsigned int is 32-bits, big ended */
>int ulog2(unsigned long val)
>{
>    unsigned long tmp;
>
>    tmp = val >> 24;
>    if (tmp) {
>        return hiBitSetTab[tmp] + 23;
>    }
>
>    tmp = (val >> 16) & 0xff;
>    if (tmp) {
>        return hiBitSetTab[tmp] + 15;
>    }
>
>    tmp = (val >> 8) & 0xff;
>    if (tmp) {
>        return hiBitSetTab[tmp] + 7;
>    }
>
>    return hiBitSetTab[val & 0xff]-1;
>}
>/*
>or even:
>*/
>typedef union {
>    unsigned long i;
>    unsigned char c[4];
>} u32bitType;
>
>/* On my machine unsigned int is 32-bits, big ended */
>int vlog2(long l)
>{
>    u32bitType val;
>    val.i = l;
>    if (val.c[3]) {
>        return hiBitSetTab[val.c[3]] + 23;
>    }
>
>    if (val.c[2]) {
>        return hiBitSetTab[val.c[2]] + 15;
>    }
>
>    if (val.c[1]) {
>        return hiBitSetTab[val.c[1]] + 7;
>    }
>
>    return hiBitSetTab[val.c[0]]-1;
>}
>#ifdef TEST
>#include <stdio.h>
>#include <stdlib.h>
>#include <math.h>
>int             main(void)
>{
>    unsigned long   l;
>    unsigned long   m;
>    unsigned long   limit = 1000000;
>
>    for (l = 0; l < limit; l++)
>    {
>        m = l*rand();
>        m =  qlog2(m), klog2(m), slog2(m), tlog2(m), ulog2(m), vlog2(m);
>    }
>
>    for (l = 0; l < limit / 100; l += 100) {
>        printf("l=%lu, klog2=%lu, qlog2=%lu, slog2 = %lu, tlog2 = %lu, ulog2 =
>%lu, vlog2 = %lu, log2=%f\n",
>               l, klog2(l), qlog2(l), slog2(l), tlog2(l), ulog2(l), vlog2(l),
>log((double) l) / log(2.));
>    }
>    return 0;
>}
>#endif



This page took 0.01 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.